Search code examples
vb.netcollectionscomboboxcontrolcollection

Create and loop through collection subset of controls


Im making a small vb.net windows form application in which I have 4 ComboBoxes. I would like to add the ComboBoxes to a collection and be able to loop through that collection to refer to each one.

There are other ComboBoxes on the form so I cannot just use the collection for the entire form (the form layout cannot be changed, e.g. to add a container, etc).

I was thinking something like the following:

Public Class Form1
    Dim IoTypeCombos As New ControlCollection(Me) From {Me.IO1_ComboBox, Me.IO2_ComboBox, Me.IO3_ComboBox, Me.IO4_ComboBox}
    Dim IoTypes As New Collection() From {"Out 0", "Out 1", "Input", "Analog"}

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        For Each cb As combobox In Me.IoTypeCombos
            FillComboBox(cb, Types)
        Next
    End Sub

    Function FillComboBox(cb As Control, cc As Collection) As Boolean
        Dim cbc As ComboBox = CType(cb, ComboBox)
        If cc.Count = 0 Then
            Return False
        End If
        For Each cn In cc
            cbc.Items.Add(cn)
       Next
       Return True
    End Function

This doesn't raise any exception, BUT it doesn't populate the ComboBoxes either :( The FillComboBox() works perfectly if I pass a single control to it. What am I doing wrong? Thanks


Solution

  • This line is illegal:

    Public Class Form1
        Dim IoTypeCombos As New ControlCollection(Me) From {Me.IO1_ComboBox, 
                    Me.IO2_ComboBox, Me.IO3_ComboBox, Me.IO4_ComboBox }
    

    That code will run before the constructor, before Me or ION_ComboBox exist. In this case, the resulting collection contains nothing since there is nothing to put in it yet.

    In other cases, referencing controls before they exist can result in a NullReference being thrown, but due to an odd bug it may not be reported. When that happens, the rest of the code is skipped and the form simply shown.

    In either case, the solution is to declare your collection at the form level, but populate it in the form load event once the controls do exist. I would also use a Collection(Of T) instead (an array or List(Of T) will also work, the OP uses/asks about a collection though):

    Imports System.Collections.ObjectModel
    
    Public Class Form1
         Dim IoTypeCombos As Collection(Of ComboBox)  ' form and controls Do No Exist yet
    
         Public Sub New
             '...
             InitializeComponent()
            ' NOW they exist
         End Sub
    
         Sub Form_Load
             IoTypeCombos = New Collection(Of ComboBox)
             IoTypeCombos.Add(IO1_ComboBox)
             IoTypeCombos.Add(IO2_ComboBox) 
             ...    
    

    If you use a List(Of ComboBox), you can populate it different ways:

     ' in the ctor:
     IoTypeCombos = New List(Of ComboBox)({IO1_ComboBox, IO2_ComboBox...})
     ' using AddRange:
     IoTypeCombos.AddRange({IO1_ComboBox, IO2_ComboBox...})