Simulating Control Arrays in VB.NET

 

Control arrays were a very useful construct in pre-.NET ("classic") versions of VB (i.e., VB6 and before), but are not supported in VB.NET. Many articles have been written to discuss this and to demonstrate how to simulate the functionality of control arrays in VB.NET. About.com has a set of articles on this, which can be viewed at http://visualbasic.about.com/od/usingvbnet/a/dykctrlarray7.htm.

 

For those not familiar with "Classic VB", some background about control arrays is in order:

 

Similar to arrays of variables, you could group a set of controls together as an array. The following facts applied to control arrays:

 

  • The set of controls that form a control array must be all of the same type (all textboxes, all labels, all option buttons, etc.)

 

  • You set up a control array by naming one or more controls of the same type the same name and set the Index property of each control in the array to a non-negative value (i.e., the controls in the control array are usually indexed from 0 to one less than the number of controls in the array). (Note: Controls in .NET do not have an Index property.)

 

  • To refer to a member of a control array, the syntax is:

 

ControlName(Index)[.Property]

 

For example, to refer to the Text property of the first element of an array of textboxes called txtField, you would use:

 

      txtField(0).Text

 

  • All the members of the control array would share the same event procedure – for example, if you have a control array of 10 textboxes call txtField, indexed 0 to 9, you will not have 10 different GotFocus events – you would just have one that is shared amongst the 10 members. To differentiate which member of the control array is being acted upon, an Index parameter would be automatically passed to the event procedure. For example, the GotFocus event procedure for the txtField control array might look like this:

 

Private Sub txtField_GotFocus(Index As Integer)

 

    txtField(Index).SelStart = 0

    txtField(Index).SelLength = Len(txtField(Index).Text)

 

End Sub

 

 

 

While many approaches to implementing control array functionality in .NET involve using special classes or collections, the approach presented here does not.

 

If I wanted a “control array” of four labels, I would do the following:

In design mode, place four labels on my form, and name them all the same, except that the last character(s) of the name would serve as the “index” (i.e., lblTest0, lblTest1, lblTest2, lblTest3) .

In the general declarations section of the form, I define a variable using the name of the control (without the index) As that type of control:

 

Public Class Form1

...

    Private lblTest As Label

...

 

The Handles clause of the event procedure(s) for the control would include all four controls:

 

    Private Sub lblTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _

    Handles lblTest0.Click, lblTest1.Click, lblTest2.Click, lblTest3.Click

 

To simply know which one you are dealing with, you can use sender.Name:

 

        Label1.Text = "You clicked on " & sender.Name

 

To get the “index” you can use code like this (in this case, the name “lblTest” has 7 characters, so I use 8 in my Mid function):

 

        intIndex = CInt(Mid(sender.Name, 8))

        Label2.Text = "The index is " & CStr(intIndex)

 

To really “use” the current control as its native type (in this case a Label), I do a “DirectCast” as follows:

 

        lblTest = DirectCast(sender, Label)

 

So now you can use normal properties of the label, such as BackColor:

 

        lblTest.BackColor = GetRandomColor()

 

(Note: "GetRandomColor" is a function in this particular example, defined as follows):

 

    Public Function GetRandomColor() As Color

 

        Dim objRandom As New Random

 

        Return Color.FromArgb(255, _

                              objRandom.Next(0, 255), _

                              objRandom.Next(0, 255), _

                              objRandom.Next(0, 255))

    End Function

 

To process the group of controls as an array, in a loop, I use the loop’s index to form the name of the current control, and I pass this name to a helper function I call “GetControlByName” within the DirectCast function. For example, below is a button which will toggle setting the text of all four labels to either blank or the word “TEST”. (The code for the helper function is shown after that.)

 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

 

        For i As Integer = 0 To 3

            lblTest = DirectCast(GetControlByName(Me, "lblTest" & CStr(i)), Label)

            lblTest.Text = IIf(lblTest.Text = "", "TEST", "")

        Next

 

    End Sub

 

The code for the helper function is:

 

   Private Function GetControlByName(ByVal pobjParent As Control, _

                                     ByVal pstrCtlName As String) _

    As Control

 

        Dim objCtl As Control

 

        For Each objCtl In pobjParent.Controls

            If objCtl.Name = pstrCtlName Then

                Return (objCtl)

            End If

        Next

 

        ' if control is not found

        Return Nothing

 

    End Function

 

The sample application (screen-shot shown below) demonstrates the concepts discussed above. Download it here.