0

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

Toby
  • 9,696
  • 16
  • 68
  • 132

3 Answers3

2

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...})
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • I get an error for `Dim IotypeCombos As Collection(Of ComboBox)` that "Microsoft.VisualBasic.Collection has no type parameters and so cannot have type arguments"... – Toby Nov 07 '14 at 15:06
  • your comment on my OP led me to use `Dim IoTypeCombos() As ComboBox` instead with `IoTypeCombos = New ComboBox() {Me.IO1_ComboBox, Me.IO2_ComboBox, Me.IO3_ComboBox, Me.IO4_ComboBox} For Each cb As ComboBox In Me.IoTypeCombos` And this does the trick – Toby Nov 07 '14 at 15:07
  • 1
    you need to add a reference to `System.Collections.ObjectModel` and import it as shown; simply using an array in the same spot wont work either - they controls do not exist yet – Ňɏssa Pøngjǣrdenlarp Nov 07 '14 at 15:07
  • The problem is this line in the [`ControlCollection`](http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs,15891d0ad5731bb2) class Add method: `if(value == null) return;` where value is the control to be added to the collection. So calling it before the InitializeComponent will result in an empty collection. – Steve Nov 07 '14 at 15:23
  • @steve, correct. It is kind of confusing when control refs will and will not work before InitializeComponent. Thought I had it figured out... Amended answer. – Ňɏssa Pøngjǣrdenlarp Nov 07 '14 at 15:47
0

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()
OneFineDay
  • 9,004
  • 3
  • 26
  • 37
0

'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