VBA - Adding a listbox to an array - arrays

I've been searching around online, and just want to know how to add a bunch of ListBoxes from my Userform to my array. Here's what I have so far:
Dim LBArray() As Variant
Private Sub UserForm_Initialize()
ReDim LBArray(7) As Variant
FirstNameTextBox.Clear
LastNameTextBox.Clear
HotelCIDate.Clear
HotelCODate.Clear
HotelNameBox.Clear
HotelConfStatus.Clear
HotelConfNumber.Clear
LBArray(0) = FirstNameTextBox
LBArray(1) = LastNameTextBox
LBArray(2) = HotelNameBox
LBArray(3) = HotelCIDate
LBArray(4) = HotelCODate
LBArray(5) = HotelConfStatus
LBArray(6) = HotelConfNumber
End Sub
This should work, but it doesn't actually add the listboxes to the array. All the elements are either "" or Null, and I can't modify the ListBox objects from the array. Anyone know why this is happening?

A listbox is an Object, so you need to use the Set keyword when assigning an object, otherwise it will return the object's default property (which in this case I think is the .Value property)
Set LBArray(2) = HotelNameBox
Etc.
I don't think it's really necessary to do this, and actually it seems unnecessary and confusing! Later in your code, you're going to need to refer to ListBox(i) or to the objects by name.
If you need to iterate over the listboxes and perform some operations on them, you can always do:
Dim ctrl as MSForms.Control
For each ctrl in UserForm1.Controls
If TypeName(ctrl) = "ListBox" Then
** Code to do something with each listbox
End If
Next

Related

How can I store an array in my.settings in vb.net

I am trying to store a user input array in a my.settings variable in vb.net. I would like for the user to enter an array in the form {1,2,3}, store that as a string in the setting and then be able to use the setting value later to create a new array. The code will be something like:
Dim inputarray()
Dim outputarray()
inputarray=textbox1.text
my.settings.inputstoredarray.add(inputarray)
outputarray=my.settings.inputstoredarray
textbox2.text=outputarray(0)
'If the user types "{1,2,3}' in textbox1, textbox2 should show "1"
I have tried multiple versions of this but there seem to always be type conversion errors. I don't understand why it works if I hardcode:
inputarray={1,2,3}
and yet the below code does not work:
inputarray=my.settings.inputstoredarray
How can I store a user provided array in my.settings and retrieve it for use later?
does not work even if I go into settings and set the string value for the setting to {1,2,3}
Set up your setting in Project Properties, Settings tab as follows.
Then save the setting as follows.
Private Sub SaveStringToSettings()
My.Settings.StringOfInts = TextBox1.Text 'User types in {1, 2, 3}
End Sub
To retrieve the setting and turn it into an array
Private Sub CreateArrayFromSettings()
Dim SettingValue = My.Settings.StringOfInts
Debug.Print(SettingValue) 'View this in the Immediate window
'Get rid of the braces
Dim TrimmedString = SettingValue.Trim({"{"c, "}"c})
'Split the string by the commas into an array
Dim Splits = TrimmedString.Split(","c)
'Get rid of the spaces
For i = 0 To Splits.Length - 1
Splits(i) = Splits(i).Trim
Next
TextBox1.Text = Splits(0) 'Displays 1
End Sub
You can browse for additional setting types in your Project properties/Settings tab but you'll find it fairly limited with the most common message being that you can't use that type. Array is one you can't use, I'm afraid.
But you can use the fully-supported StringCollection:
Dim saveTest As New StringCollection() From {"1", "2", "3", "4"}
My.Settings.MySetting = saveTest
My.Settings.Save()
Dim loadTest As StringCollection = My.Settings.MySetting
Another option would be to use, say, and XML or JSON string that you de-serialize but that's getting a bit involved.
You can't store an array in application settings. What you can do is create a setting of type StringCollection. You can then use it as a StringCollection in code or you can transfer the data back and forth between the StringCollection and an array if you really need an array.
Start by opening the Settings page of the project properties and creating a new setting of type System.Collections.Specialized.StringCollection. For this example, I'll name it MyStringCollection but you should name it appropriately for your app. When you do this, notice that the Value field is empty by default. This means that the setting is Nothing by default. That's OK but it means that you need to actually create the collection object in code before using it for the first time, e.g.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
If My.Settings.MyStringCollection Is Nothing Then
My.Settings.MyStringCollection = New StringCollection
End If
'Use My.Settings.MyStringCollection here.
End Sub
Alternatively, you can force the settings UI to create the object for you. To do that, select the Value field for that setting and click the browse (...) button. Add any arbitrary character and click the OK button. Notice that the Value field is populated with an XML snippet that contains the text you entered. Click the browse (...) button again, delete the text and click OK again. Notice that the XML remains, even though the text you had entered is removed. That XML will now create the StringCollection object automatically, so you don't need code to do so.
If you're happy wiith a collection of String values then you can use the setting directly in code wherever you like. It works, for the most part, like a List(Of String), allowing you to add and remove items at will. If you specifically need an array or you need a type other than String then you will have to do some translation, e.g.
'Load the collection items into a String array.
Dim myStringArray = My.Settings.MyStringCollection.Cast(Of String)().ToArray()
'Load the collection items into an Integer array.
Dim myIntegerArray = My.Settings.MyStringCollection.Cast(Of String)().Select(Function(s) CInt(s)).ToArray()
'Repopulate the collection from a String array.
My.Settings.MyStringCollection.Clear()
My.Settings.MyStringCollection.AddRange(myStringArray)
'Repopulate the collection from an Integer array.
My.Settings.MyStringCollection.Clear()
My.Settings.MyStringCollection.AddRange(myIntegerArray.Select(Function(n) n.ToString()).ToArray())
If you want to display the contents of your collection in a TextBox than you might do something like this:
TextBox1.Text = String.Join(",", My.Settings.MyStringCollection.Cast(Of String)())
That will create a single, comma-delimited String containing all the items. To repopulate the collection from a TextBox containing such text, do this:
My.Settings.MyStringCollection.Clear()
My.Settings.MyStringCollection.AddRange(TextBox1.Text.Split(","c))

VBA Array Public Method cant be modified by components

I'm working with a rather complex problem in VBA and I decided to structure it in different classes.
One of the classes containd an array and I need to modify the component individualy outside the class.
The problem can de reduced to the definition of the class
Public a As Variant
Private Sub Class_Initialize()
ReDim a(5) As Double
' Set some value
a(1) = 20
End Sub
And a sub to access the data:
Sub Test()
Dim b As New DummyTest
b.a(4) = 7
Debug.Print (b.a(1))
Debug.Print (b.a(4))
End Sub
The result on the debug window is 20 0. I've checked this result with an inspection and confirm that the property a cannot be modified from the exterior of the class.
Funny part is that the property can be modified if replaced by other array, for example:
Sub Test2()
Dim b As New DummyTest
b.a = Array(1, 2, 3, 4, 5)
Debug.Print (b.a(1))
Debug.Print (b.a(4))
End Sub
Behaves as expected. I'm confused as element access is allowed inside the class context and in any other situation, but in this specific case it doesn't wotk. There is no error msg, it simply refuses to change the content of the array.
I'll find work around solutions but missing this way to access data is being a really PITA.
Hope you can help me with this issue.
Thank you in advance!
Your "property" is breaking encapsulation, which pretty much defeats its entire purpose.
Public a As Variant
From a public interface standpoint, this is a read-write property (if you added a new class module with Implements DummyTest you'd have to add Property Get and Property Let members for it). From the class' standpoint, it's a public instance field.
When a class encapsulates an array, a collection, a dictionary, or any other data structure, the last thing you want is for that data structure to be publicly exposed, with anyone anywhere being able to just overwrite the class' entire internal state as it pleases - you're not getting any of the advantages of classes that way.
First step to proper encapsulation is to make the instance field Private. Next step is to expose actual Property accessors. You want the array data to be writable? Expose an indexed Property Let member for it.
Private a As Variant
Private Sub Class_Initialize()
ReDim a(0 To 10)
End Sub
Public Property Get Value(ByVal index As Long) As Variant
Value = a(index)
End Property
Public Property Let Value(ByVal index As Long, ByVal newvalue As Variant)
a(index) = newvalue
End Property
This code behaves exactly as advertised:
Public Sub Test()
Dim b As DummyTest
Set b = New DummyTest
b.Value(4) = 7
Debug.Print b.Value(1)
Debug.Print b.Value(4)
End Sub
Note that because the array is encapsulated, that client code is absolutely unable to re-assign the array itself: the array is abstracted away and only accessible through the means exposed by the class.
Reference variable in VBA must be declared, so that we know what type of object we are referring to
i.e. Dim b As DummyTest ' No new required in this step
Before using a declared reference to store information create an instance of the Class.
i.e. Set b = New DummyTest
This might seem confusing but is actually very logical. Because b is a Class the Dim statement sets up b to hold the address of a DummyTest object. At the time of the Dim statement no object has been created (no memory allocated) so the address of b is nothing (no value or null). The set statement tells VBA to create an instance of your DummyTest class (allocate the memory it needs) and puts the address of the instance (memory) into variable b. Then because VBA knows that b points to an instance of a class you never see the address of b when you use it, just the data to which b is pointing. You can get the the address b is holding using the function Objptr but this is only something you would do in very special/specific circumstances

Array as an argument in a procedure vb6 vs vb.net

Here it is a procedure in vb6 and it is working fine like the example included:
' Check_UnCheck
' check an array of some checkboxes, uncheck an array of another checkboxes
' Example of usage :
CheckBox.Check_UnCheck Array(chkCheck3, chkCheck5), Array(chkCheck1, chkCheck4)
Public Sub Check_UnCheck(ByRef CheckArray As Variant, ByRef UnCheckArray As Variant)
Dim i As Integer
Dim conControl As Control
For i = LBound(CheckArray) To UBound(CheckArray)
Set conControl = CheckArray(i)
conControl.Value = 1
Next
For i = LBound(UnCheckArray) To UBound(UnCheckArray)
Set conControl = UnCheckArray(i)
conControl.Value = 0
Next
End Sub
what is the equivalent in vb.net for the above procedure, the MSDN Documentation says :
We cannot use more than one parameter array in a procedure, and it must be the last argument in the procedure definition.
Try below code.
Look into comments for detailed description.
'DECLARE YOUR ARRAYS.
Dim array1 = New CheckBox() {CheckBox3, CheckBox5}
Dim array2 = New CheckBox() {CheckBox1, CheckBox4}
'CALL CHECK AND UNCHECK FUNCTION.
Check_UnCheck(array1, array2)
'YOUR FUNCTION DEFINITION.
Public Sub Check_UnCheck(ByRef CheckArray As CheckBox(), ByRef UnCheckArray As CheckBox())
'LOOP FIRST ARRAY AND CHECK THEM.
For index = 0 To CheckArray.GetUpperBound(0)
CheckArray(index).Checked = True
Next
'LOOP SECOND ARRAY AND UNCHECK THEM.
For index = 0 To UnCheckArray.GetUpperBound(0)
UnCheckArray(index).Checked = False
Next
End Sub
First you are confusing "parameter array" with an array of controls, they are not the same thing. A parameter array is when a method takes a variable number of parameters (all of the same type), the compiler then bundles those up into an array and passes that to the method. In order for that to happen the method has to use the keyword ParamArray.
VB.net does not have conrtol arrays in the sense that vb6 did, but that isn't what you example is using. You example is using a simple array of controls. As an aside, your example is using ByRef which was the default in VB6, but it is unnecessary in this case for both VB6 and VB.net. Given that it's usage in VB.net is no longer the default, using it unnecessarily is misleading.
You are passing in two arrays, the second could be a ParamArray but there is little point in doing so.
The basic and minimum change to get your code to work is simple, change the "Variant" to "CheckBox()". But that is not what I would recommend. There are a couple of other minor changes that make it more flexible and more readable.
Public Sub Check_UnCheck(CheckArray As IEnumerable(Of CheckBox),
UnCheckArray As IEnumerable(Of CheckBox))
' Here I have replaced the Variant, which is not supported in
' .net, with the generic IEnumerable of checkbox. I used an
' Ienumerable, instead of an array because it will allow making
' just a minor change to the call site.
' here I have eliminated the index variable, and moved the
' declaration of the conControl variable into the for each.
' Option Infer On statically types the variable as a checkbox
For Each conControl In CheckArray
' Checkbox controls do not have a value property.
' 1 is not true, true is true.
conControl.Checked = True
Next
For Each conControl in UnCheckArray
conControl.Checked = False
Next
End Sub
This would then be called like so:
Check_UnCheck({chkCheck3, chkCheck}, {chkCheck1, chkCheck4})

Is it possible to create an Array of Collections in VB.net or is it bad practice? What other replacements with the same function exist?

I am creating an app that has to create controls with specific parameters (some of which are custom parameters used for other applications) so the original method was like this
PSEDO CODE(kinda)
Dim ControlType1Color() as color
Dim ControlType1Name() as string
Dim ControlType1Parameter() as string
...
Dim ControlType2Color() as color
...
However when implementing that notation it ends up causing me to do quite a few test statements in order to recognize which type of control it is, Then find the correct variable to use. Which is honestly a waste of code space which could be saved.
While I was researching for something similar to java Objects (i believe?) I came across collections which should be what I need. However I need to know how I can implement it for this? Does a collection have infinite length? Can you use it as an array? And can you nest it with an array so you have an Array of Collections or is that just unnecessary?
EDIT FOR CLARIFICATION:
I am trying to record my controls that I created in run-time basically and try to use a single variable to record all Data
Lets say I have two textboxes and one button
My "Array of Collections" or whatever it would be would be like
AoC(0).Color = color
AoC(0).Type = Textbox
AoC(0).ID = ID
Aoc(1).Type = Textbox
...
Aoc(2).Type = Button
...
So if I needed to change anything I just change this thing only. I can handle the actual changes in code, I just need to know how to store it in the memory without using 5-15 variables needlessly.
You need to do something like this:
Private Structure ControlDetail
Public Color As System.Drawing.Color
Public ControlType As Type
Public ID As String
End Structure
Then you can define your data as:
Dim Aoc = New ControlDetail() _
{ _
New ControlDetail() With { .Color = System.Drawing.Color.Red, .ControlType = GetType(TextBox), .ID = "txtFoo1" }, _
New ControlDetail() With { .Color = System.Drawing.Color.Blue, .ControlType = GetType(Button), .ID = "butFoo2" } _
}
Then you can get access to the data as Aoc(0).ID, for example.

Excel VBA Object Variable Not Set issue, possible improper Redim usage?

I am running into an error with the below code. When I debug, I find the line causing my problem:
Options(a) = New Element
The error displayed is Object Variable or With Block Variable Not Set. With msg boxes I have found the value of a to be 0 at the time of the crash and the TotalItems to be 7. The Element object initialization is empty. I call the PopulateChildren method from another method within the same class. Am I using ReDim improperly? It seems like maybe it isn't increasing the size of my array... I have noticed examples of using it like this...
ReDim Preserve Options(0 to TotalItems)
...but it doesn't seem to do any different when I try it. Anyone have any idea what is going on?
Dim Options() As Element
Dim TotalItems As Integer
Dim Children(100) As Integer
Private Sub PopulateChildren()
ReDim Preserve Options(TotalItems)
For a = 0 To TotalItems - 1
Options(a) = New Element
Options(a).Populate (Children(a))
Next a
End Sub
Thanks
Since Element is Object, you should use Set:
Set Options(a) = New Element
easy, put your dim options inside the SUB, or ...
public dim options()
sub ...
'your code
end sub
of course options doesn't exit for your sub like you wrote it ! so the error showing...

Resources