This probably will seem like a simple process, but I'm new to programming, so I don't know how to do it.
I'm programming in VB.Net and I want the computer to generate a new set of global variables every time the user presses Button X. Naturally we don't know how many times the button will be pressed, which is why I need the computer to create the variables. Also, how do I tell the computer to assign a new number to each variable? For example:
ButtonX clicked first time:
NewVariable1 created
ButtonX clicked a second time:
NewVariable2 created.
I hope this makes sense. I can provide more details if necessary. I need the variables generated to be accessible from many different classes, and maybe even from one load to the next, if possible.
Have a look at the List(Of T) class. Create a list that is globally accessible and add another value each time the button is pressed.
globaList.Add(newValue)
This assumes that all the variables are of the same type.
Later on, you can access the list items (=variables) by their index. This retrieves the value that was added last:
Dim value = globalList(globalList.Count - 1)
You can also change values in the list:
globalList(index) = newValue
Related
I'm trying to optimize the performance of my access frontend. One of the problems I'm stumbling on is how to set a multi-window form to open immediately to a specific record, because at the moment it queries everything twice.
Essentially, I allow my users to open multiple instances of a form. That way, a user can compare multiple records by placing the windows of those forms side by side.
At the moment, my code looks like this:
Set frm = New Form_Name
frm.RecordSource = "select * from Table where id = " & ID 'ID is a variable passed to the method
I'm pretty sure back then this question was one of the building blocks I relied on.
The problem is that on the first line, access already entirely opens the form and does everything the form does when opening, such as Form_Open, Form_Current, and loading subforms. Then, when I set the recordsource, it does all (or most) of that again, which significantly slows down the process of opening the form.
Here are some of the things I've tried:
Changing the Form_Current to recognize that it's being "used" twice and only actually run the code once. The problem is that the code is already very optimized and doesn't seem to be the bottleneck, so this doesn't seem to do much. Actually opening the form seems to be the bottleneck.
Trying to change the properties of the original form so that it opens the specific record I need, but I can't seem to change the properties without it opening the form.
Looking for a way to supply arguments to the form. That doesn't seem to be supported in VBA.
One other idea that popped into my mind was creating a variable in vba with the ID of the record, setting recordsource in the form properties to fetch that variable, but then, when I would open another form and change that ID, the form
I realize that I can do this with DoCmd.OpenForm, but that doesn't give me the option to open multiple instances of the same form.
How can I achieve this? This would mean a significant performance improvement.
OK, so I actually wanted to ask this question. But just before I hit the submit button, I had an idea...
Here's the idea: you set a global variable in VBA, which you then access in the form filter command. In my case I just added Public OpeningID As Long at the top of my VBA module. Then I create a function to get that value:
Public Function getFormID() As Long
getFormID = OpeningID
End Function
Then, in the form, you can set the filter criteria as ID = getFormID(). And then when you open the form instance, you do it like this:
OpeningID = ID
Set frm = New Form_Name
OpenindID = 0 'reset this to make sure that if it's being accessed when it shouldn't, it generates a clear error
The only problem is what happens when you refresh the form, as that will call the method again. When you refresh the form via VBA, you can set the OpeningID beforehand, and to avoid users refreshing the form, you can add this to your form (don't forget to turn on Key Previews in the form settings):
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyF5 Then KeyCode = 0
End Sub
Bang. Forms open almost twice as fast. Awesome.
My program creates an array of checkboxes at runtime as shown below:
For Looper = 0 To 36
Dim Ex1ConfigCheck As New CheckBox
frmSetup.Controls.Add(Ex1ConfigCheck) ' Add Control to from
Ex1ConfigCheck.Top = (Looper + 45) + (Looper * 18) ' Set Location
Ex1ConfigCheck.Left = 210
Ex1ConfigCheck.Text = Setup.ExCheckName(Looper) ' Set Text property from strArray
Next
This is where I don't know how to proceed.
I would like to fill a boolean array (ex. MyBoolean(37)) with the value of Ex1configCheck().Checked. The reason I would like to fill another array is because I need to be able to reference the value of the checkboxes in other parts of the code but can't access them until they are created. Also, I plan on saving the array out to a binary file.
Could someone point me in the right direction please?
If there are no other CheckBoxes in the same container as those ones then you can do this:
Dim flags = Me.Controls.OfType(Of CheckBox)().
Select(Function(cb) cb.Checked).
ToArray()
If the controls are in a different container than the form itself, replace Me with that container.
As suggested by #Jimi, you could also create a List(Of CheckBox) and assign that to a field, populating it when you create the controls. You can then use that list instead of creating one on demand:
Dim flags = myCheckBoxList.Select(Function(cb) cb.Checked).
ToArray()
Of course, if you know exactly how many CheckBoxes you are going to be adding, why do you need to wait until run time to create them? Why can't you create them at design time and then modify them at run time? You usually only create controls at run time if you don't know how many there will be until run time, but that seems not to be the case here.
Thanks all for your answers and comments. I always have a fear of being roasted when I ask what some may consider a simple question online.
I have found an alternative way of accomplishing my task. Instead of creating 8 "Arrays" of checkboxes, I have learned of a very simple control available called "CheckedListBox".
I really didn't need to create the checkboxes at runtime but was trying to find an easier way to create 8 groups of 37 checkboxes without having to manually name and set the properties of each one during design. I also wanted to be able to index them in my code to be able to update and read the value using simple loops. I could have done this by creating arrays of CheckBox but again, I would have had to manually initialize the arrays.
Once I found the CheckedListBox, I was able to accomplish what I want very quickly. I only had to set the properties of the 8 "groups" (CheckedListBox's) and fill them using the items property. The ListBox essentially created a List like Jimi suggested automatically and I can index thru each list with a loop as desired. Jimi's suggestion actually lead me to finding the CheckedListBox while I was searching for more information on using "List(of CheckBox)".
Sometimes talking to others helps me find the right questions to ask. Google was able to figure out what I wanted when I searched for "List(of CheckBox)". (:
I just started rewriting an application from vba (Access) to vb.net + SQLServer so not very experienced in .net.
I am creating custom controls (Form + form controls) with a number of extra properties PrevValue, Modified (similar then the one of Textbox), Dirty, DirtyEnabled, SQLColumnName, SQLTableName to enable AutoUpdating and undoing in my forms the form exposes IsDirty, Initialising and Isready properties and an undo method.
Doing so it occurs that I have to write 3 times the same iteration code in different places:
For each Ctrl as Control in frm.Controls ' frm being a reference to the form
if typeOf Ctrl is MyTextBox
with DirectCast(Ctrl, MyTextBox)
' here comes the variable code depending what needs to be done
end with
elseif TypeOf Ctrl is MyComboBox
' etc.... for MyListBox, MyCheckBox etc....
I also have a number of custom controls MyNumBox and MyDateBox that inherit from MyTextBox but with some modified behavior (Formula evaluation, date manipulation, calendar...) how do I avoid doing an extra test on them.
One version of this Iteration is in the SQLProcessClass where the modified controls are added as SQLParameter and after iteration calling the SQLProcessClass Update or Insert, but ... after successful SQL activity I need to iterate through the controles again to reset the modified flag for each control. Elsewhere I need it to implement a form undo to reset all the controls to their previous values.
It seems to me I have two options
1. repeating that iteration code everywhere I need to iterate through the forms controls. I don't like it as every time I would need to create a new custom control I have to add some lines X times in different modules/classes ... very bad programming
2. Creating one form iteration procedure containing all the different activities that normally belong to another class within that "centralised" procedure, that could be better then (1) but I don't like it that much either.
Is there a better way of doing it using some .net functionality I don't master yet ?
Thanks for any advise.
Iterating through from controls can be tricky since controls are often nested. A more controlled approach would be to add another collection object to your form where you keep references to your added controls.....
e.g
Dim My_Widgets as New List(of Your-Control-Class-Name)
Then when you create the controls to the form also add them to that list.
My_Widgets.Add(Widget_Object)
After that it is a simple matter to iterate through that list.
For Each Widget as My_Widget_CLass in My_Widgets
' do what you need to do to Widget
Next
If you need to reference individual controls directly, use a dictionary object instead..
e.g.
Dim My_Named_Widgets as new Dictionary(of String, Your-Control-Class-Name)
Then add your control references to the dictionary by name
My_Named_WIdgets.add("<Whatever_You_USe_To_Identify_It>", Widget_Object)
You can then reference the specific control by the ID or name
My_Names_Widgets("ID").Property = Whatever '... etc
You seem to be indicating you have other controls for other purposes, as such it would be prudent to create similar collections for each type.
Hey guys very new here.
Have a listbox that gets account names from a specific game server using this command line
Dim apikeyinfo As APIKeyInfo = api.getApiKeyInfo()
lstbxCharacters.DataSource = apikeyinfo.Characters
this code gets all the characters in a single account by displaying it in a listbox.
Now i would like to reference a character from the lisbox but not sure how
Any method such as Listbox.Get to get the value and compare it with something else?
Thanks
you can try something like
lstbxCharacters.SelectedItem
Update
To read the data from the listbox I think there are multiple ways (Assuming that it is readable).
-> Usually listbox display strings, so it should work to read to a string variable
Dim a_string as Strin = lstbxCharacters.SelectedItem
also you may like to add a small check before, assuring that an Item is currently selected:
If lstbxCharacters.SelectedIndex < 0 then return
This jumps out of current sub if no item is selected
And finally, to read the first entry, you can also do it this way:
a_string = lstbxCharacters.Items(0)
if it returns objects, then instead of accessing the object directly, it may work to do
a_string = lstbxCharacters.Items(0).ToString
(most objects allow a .ToString() Function )
Here two ideas for different solutions:
As a user commented, you could access the DataSource directly + the information which listIndex was selected. But if you do so, then maybe it is more easy (if you need to access it anyways, to go with solution 2)
Create a variable of type list(Of some_object) and fill it with the data from the datasource. It will take some time to do this, but if you define for the class some_object a function ToString, then you can fill all objects directly to the lstbxCharacters, and access them without any worries, by doing CType(lstbxCharacters.SelectedItem, some_object)
Update 2
If with reference you mean to access further information from the datasource, then you need to build some kind of query, or set the content of the listbox in relation to another control that shows the database content (in that way the listbox lstbxCharacters would act like a filter)
In vb.net, you can address a public variable from another form using the form name along with the variable.
form2.show
form2.k = 3
However, if you use a form variable to show an instance of the form, you must use that variable name to address the public variable. Two instances of the same form are displayed in the following example. The public variable k is assigned a value of 3 only in the first instance of the form, the one from form2.show. frm.k can be used to assign a value to the other form.
dim frm as new form2
form2.show
frm.show
form2.k = 3
My question: Assuming only one instance of the form is shown in the application, is it reliable to address a public variable using the form name (form2.k), or is it better to show the form with a form variable and use that to refer to the instance of the form (frm.k)? Would the same answer apply to a property as well as a public variable?
Little bit of clarification here. In the case of using the form name to access the variable you are still using an instance to access the variable. It's a feature of VB.Net called the default instance. Essentially VB.Net will maintain a single instance per form type. Under the hood it will translate your code to access this instance variable. This was a very popular feature of VB6 which was ported to VB.Net (in 2005 I believe).
The case where a form is shown once is the exact case this feature was designed for. So yes it's reliable to use it to access the value. This applies to any instance member.
This is of course assuming everything is single threaded.
Definitely #2, use the instance variable. I didn't know that the other syntax still worked! That was a leftover from VB4 that was moved to VB6 for compatibility. I thought they dumped it in .net. Don't think it would even work in C#.