Getting Data into and out of multiple ListBox like an array?

robward

New member
Joined
Dec 19, 2007
Messages
4
Location
Lakes Entrance, VIC, Australia
Programming Experience
3-5
Having gone from VB6 to Java to VB.Net, I have some fond memories of creating control arrays in VB6 that allowed me to set an index value on the control and if I copied and pasted, VB6 simply created a control with an incremented index. Lovely! When I learned Java it had to be done OOP compliant and very elegant it was too. Now that I have returned to the VB fold as VB.Net, I cannot replicate this very convenient concept. I have spent literally days searching the net, but to no avail. The closest I have come is to set up a Panel and place multiple ListBox in them and trap all the events associated with each ListBox, instantiate the object passed and read the value from the ListBox that cause the event.

However this does not allow automatic indexing of the ListBox out of the 7 source ListBox possibilities, nor, just as importantly, can I see how I can index data back into any one of the other 7 destination ListBox values?

In a nutshell, the problem is this, I have seven ListBox that I get 4 values from and feed into a parallel set of 7 ListBox and also into String arrays, how can I do this in the most efficient way without having, long lines of IF/THEN statements to transfer the data from one list box to its corresponding ListBox?

Is there an easy answer or is in OOP and VB.net somewhere?

Cheers.
 
You're thinking like there has to be some special mechanism for this specifically. There doesn't and there isn't. You can use one event handler for multiple controls just as you can for any objects. It's for that reason that the design-time support of VB6 control arrays no longer exists. The .NET event handling mechanism makes it obsolete.

As for arrays of controls, you can make an array of ListBoxes just as easily as you can make an array of Integers or Strings. In an event handler the sender is the object that raised the event and it's quite easy to determine the index of that object in an array.
VB.NET:
Private listBoxes As ListBox()

Private Sub Form1_Load(ByVal sender As Object, _
                       ByVal e As EventArgs) Handles MyBase.Load
    Me.listBoxes = New ListBox() {Me.ListBox1, _
                                  Me.ListBox2, _
                                  Me.ListBox3}
End Sub

Private Sub ListBox3_SelectedIndexChanged(ByVal sender As Object, _
                                          ByVal e As EventArgs) Handles ListBox3.SelectedIndexChanged, _
                                                                        ListBox2.SelectedIndexChanged, _
                                                                        ListBox1.SelectedIndexChanged
    Dim index As Integer = Array.IndexOf(Me.listBoxes, sender)

    MessageBox.Show("The ListBox at index " & index & " just changed its SelectedIndex.")
End Sub
I should also point out that there is plenty of ink dedicated to doing in VB.NET what you did in VB6 with control arrays. There are several topics on MSDN for a start, which is always the first place you should be looking for .NET-related information.
 
Good use of Lists

Thanks jmcilhinney,

Your reply neatly summarises some of my previous explorations, such as using events to trap different components, and I appreciate the elegant way of making an array of the components.

However I am still unclear how I can use the array concept to index data back into the parallel array ListBoxes.

eg DestinationListBox(0).item.additem = SourceListBoxSource(0).selecteditem

Thank you for your assistance and I can reassure you I searched high and low and because I must have not used some key words in the search may have missed the MSDN info, or it did not really fit the bill.

Cheers, RobWard
 
I'm not sure what the problem is. You've got the index of the ListBox that raised the SelectedIndexChanged, therefore you can get the SelectedIndex of that ListBox. The index of the corresponding data in any parallel arrays or supposedly linked ListBoxes will be the same.

That said, this is an extremely clumsy way to go about this. What you should be doing is defining a type that has a property for the value to go in each ListBox. You then add multiple instances of that type to a collection, which you then bind to each and every ListBox via a BindingSource. All ListBoxes will remain in sync, courtesy of the data-binding mechanism, and you can always get related values together as a single object from the BindingSource. Try implementing these steps to see an example of what I mean:

1. Create a new WinForms project.
2. Add three ListBoxes and one BindingSource to the form.
3. Add the following code:
VB.NET:
Public Class Form1

    Private Class Thing

        Private _id As Integer
        Private _name As String
        Private _date As Date

        Public Property ID() As Integer
            Get
                Return Me._id
            End Get
            Set(ByVal value As Integer)
                Me._id = value
            End Set
        End Property

        Public Property Name() As String
            Get
                Return Me._name
            End Get
            Set(ByVal value As String)
                Me._name = value
            End Set
        End Property

        Public Property [Date]() As Date
            Get
                Return Me._date
            End Get
            Set(ByVal value As Date)
                Me._date = value
            End Set
        End Property

        Public Sub New(ByVal id As Integer, ByVal name As String, ByVal [date] As Date)
            Me._id = id
            Me._name = name
            Me._date = [date]
        End Sub

    End Class

    Private Sub Form1_Load(ByVal sender As Object, _
                           ByVal e As EventArgs) Handles MyBase.Load
        Dim things As New List(Of Thing)

        things.Add(New Thing(0, "Something", #1/2/2007#))
        things.Add(New Thing(1, "Nothing", #5/9/2000#))
        things.Add(New Thing(2, "Everything", #12/24/1953#))
        things.Add(New Thing(3, "Plaything", #10/2/1856#))
        things.Add(New Thing(4, "Thing King", #9/4/1989#))

        Me.BindingSource1.DataSource = things

        Me.ListBox1.DisplayMember = "ID"
        Me.ListBox1.DataSource = Me.BindingSource1

        Me.ListBox2.DisplayMember = "Name"
        Me.ListBox2.DataSource = Me.BindingSource1

        Me.ListBox3.DisplayMember = "Date"
        Me.ListBox3.DataSource = Me.BindingSource1
    End Sub

    Private Sub BindingSource1_CurrentChanged(ByVal sender As Object, _
                                              ByVal e As EventArgs) Handles BindingSource1.CurrentChanged
        Dim t As Thing = DirectCast(Me.BindingSource1.Current, Thing)

        MessageBox.Show(t.ID & " " & t.Date, t.Name)
    End Sub

End Class
4. Run the project.
5. Try clicking on different items in different ListBoxes and observe.
 
Looks good, what do you think?

Thank you John,
I have used some of your advice and found a solution that I am happy with at the moment. I would be interested in your comments if you can see improvements or alternatives. Sorry to be tardy with a reply but the festive season has taken it toll in spite of all the broadband improvements.
I have three ListBox'es on a GUI inside a GroupBox1. This seemed to improve the determination of the index event. Thank you for the concept of instantiating "sender" to determine the index. The way I have set up the arrays allows access to the ListBox in both "setting or getting" data which was the goal. I would like a way of more concisely loading the Arrays with the actual ListBox'es. eg inside the {} 's

I have also added a couple of buttons to exercise the example.

VB.NET:
Public Class Form3

    Inherits System.Windows.Forms.Form
    Dim myArray() As ListBox = New ListBox(3) {}

#Region " Windows Form Designer generated code "

#End Region

    Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        myArray(0) = LB0 'A ListBox on the GUI
        myArray(1) = LB1 'A ListBox on the GUI
        myArray(2) = LB2 'A ListBox on the GUI
        Dim col, row As Integer
        For col = 0 To 2
            myArray(col).Items.Clear() 'access the ListBox through the array+indexes
            For row = 0 To 5
                myArray(col).Items.Add("LB Col=" & Str(col) & " Row=" & Str(row)) 'write to the ListBox through the array+indexes
            Next
        Next
    End Sub

    Private Sub LB012_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles LB0.SelectedIndexChanged, LB1.SelectedIndexChanged, LB2.SelectedIndexChanged
        'Gather the events from the three ListBox'es
        Dim index As Integer = Array.IndexOf(myArray, sender) 'The really nice bit!
        MessageBox.Show("A ListBox Event occured at index " & index & ".")
        statusLbl.Text = myArray(index).SelectedItem
    End Sub

    Private Sub demoBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles demoBtn.Click
        statusLbl.Text = myArray(0).SelectedItem & " + " & myArray(1).SelectedItem & " + " & myArray(2).SelectedItem
    End Sub

    Private Sub quitBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles quitBtn.Click
        Me.Close()
    End Sub
End Class
I have chopped out the GUI bits from the code, but the code above should be enough.

Cheers RobW
 
First of all, you're creating an array with 4 elements when you only have 3 ListBoxes. This line:
VB.NET:
Dim myArray() As ListBox = New ListBox(3) {}
creates an array with an upper bound of 3, i.e. indexes 0, 1, 2 and 3.

Secondly, there is no way to populate the array where you declare it. The LisBoxes themselves don't exist at that point. The earliest you can populate the array is in the constructor, after the call to InitializeComponent. It is in the InitializeComponent method that all your design-time controls and components are created, so after that the ListBoxes do exist and can be assigned to array elements. I would suggest that you create the array the way I did in post #2, which is why I posted it.
 
Goal!

Thanks again John,
I was hoping there would be a natty way of doing the {} style of loading the array after the GUI was set up, but as you say, the components have not been created at the earlier declaration point. Either way, two of my major projects have made leaps and bounds with this new information and have close to a level of compactness and simplicity that I was looking for.
Cheers and thanks once again, Rob
 
Back
Top