'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 1:[1]

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...})

Solution 2:[2]

Not sure if you need the where clause, but if you have other comboboxes that do not have names like this and do not want them in the collection then you do need it.

Dim IoTypeComboboxes = 
    Me.Controls.OfType(Of Combobox)().Where(Function(cb) cb.Name.StartsWith("IO")).ToList()

Solution 3:[3]

'on yourFormName 'added : '45 PictureBox:("PicBarNum1_NotLastOdig" to "PicBarNum45_NotLastOdig") 'added: '45 PictureBox:("PicBarNum1_UkOdig" to "PicBarNum45_UkOdig")

Public Class yourFormName

Private picbarlistNum1to45_UkOdig As New List(Of PictureBox)

Private picbarlistNum1to45_UkLastNotOdig As New List(Of PictureBox)

Private sub yourFormName_Load

Call AddPicBoxesInList_OdigNoOdig()

End sub

Private Sub AddPicBoxesInList_OdigNoOdig()

picbarlistNum1to45_UkOdig.Clear()

picbarlistNum1to45_UkLastNotOdig.Clear()

picbarlistNum1to45_UkOdig = Me.Controls(0).Controls.OfType(Of PictureBox)()

.Where(Function(pb) pb.Name.StartsWith("PicBarNum") And

pb.Name.EndsWith("_UkOdig")).ToList()

picbarlistNum1to45_UkLastNotOdig = Me.Controls(0).Controls.OfType(Of

PictureBox)().Where(Function(pb) pb.Name.StartsWith("PicBarNum") And

pb.Name.EndsWith("_NotLastOdig")).ToList()

End Sub

End Class

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 OneFineDay
Solution 3 YourFriend