Dynamically Creating Control Arrays in VB.NET 2003


I have seen a lot of questions and solutions here about the issue of not being able to use control arrays in VB.NET the way we used to be able to do it in VB6. After much research and playing around with some examples I found here on Experts-Exchange, I decided I should share what I discovered so everyone can benefit. I am assigning points to this simply because I am a newbie to VB.NET and I would appreciate any feedback that could enhance what I have put together or if someone can determine that there are problems with what I did and are able to offer fresh ideas.

For my application I have a MS Access database table for digital Outputs (used to turn things on and off in the physical world). For each project we build, the number of digital outputs is different. The database table contains multiple fields but the two most important are the 'SensorID' and the "NameLong". The 'SensorID' field is the PK in this table. The 'NameLong' field is the descriptive text of the function of what the checkbox does. For the user to better understand what these do I need to provide both the 'SensorID' and the 'NameLong' as the text for the checkbox. What I needed to do was create a checkbox on a specific tab on a form for each of the digital Outputs in the database table.

At Form Level I have this:
Dim cbx() As CheckBox

I then have the following subroutine in the form code that gets the data from the database table and dynamically creates the checkboxes and sets their properties. Most of the code below should be self explanatory but I have added some comments:

Public Sub SetupICdigOut()
        Dim i As Integer
        ' constr is the connection string for the system database
        ' constr is defined in ProjConst.vb code
        Dim conn As New OleDb.OleDbConnection(constr)
        Dim strSql As String
        strSql = "SELECT SensorID, NameLong, NameShort, SlotNumber, ChannelNumber, OrderNum "
        strSql = strSql & "FROM DIG_OUT_Definition ORDER BY OrderNum"

        Dim da As New OleDb.OleDbDataAdapter(strSql, conn)
        Dim dt As New DataTable

        Dim digOutCount As Integer = dt.Rows.Count  'how many dig outputs are there?

        ReDim cbx(digOutCount)  'set array dimension based on the number of Dig Outputs in database table

        i = 0   'cbx(0) to cbx(numOfCheckBoxesNeeded-1)
        For Each dr As DataRow In dt.Rows
            cbx(i) = New CheckBox
            cbx(i).Name = "chkBx_" & CStr(dr.Item("SensorID"))  'give it a name based on the PK in database
            cbx(i).Left = 50                                    'set the LEFT position of the checkbox
            cbx(i).Top = 10 + i * 30                            'set the TOP pos. based on which checkbox it is
            cbx(i).Text = CStr(dr.Item("SensorID")) & "  " & CStr(dr.Item("NameLong")) 'create the TEXT by combining the SensorID and NameLong fields with a space in between
            cbx(i).Width = Len(cbx(i).Text) * 7     'multiply num of chars by 7 to get proper width
' I multiplied by 7 because it was the smallest number that would allow a single character to fit based
'on the default font - for larger or BOLD fonts 7 would need to be increased
            cbx(i).Visible = True                   'make the control visible
            cbx(i).Tag = i                          'use Tag as a way of addressing the specific checkbox
'it appears from my testing so far that .Tag works like an INDEX in this case.
            Me.TabDigOut.Controls.Add(cbx(i))       'add this specific checkbox to the specific tab on the form
            AddHandler cbx(i).CheckedChanged, AddressOf cbx_CheckedChanged  'AddHandler
            i = i + 1  ' increment i by one for the next subscript
    End Sub

Finally, I needed to see how the system reacted to checking and un-checking the checkboxes so I tried a few things that just popped up message boxes. Most of these are commented out below but they do work. The stuff in the IF-ELSE-ENDIF is just there for my debugging purposes for now. I will add the actual code later as I continue my development. But as you can see, this does work.

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

        'MsgBox(sender.text)     '   This will provide the TEXT of the CheckBox
        'MsgBox(sender.name)     '   This will provide the NAME of the CheckBox
        'MsgBox(sender.tag)      '   This will provide the TAG (or 'INDEX') of the CheckBox)

        'Any code can go in the IF - ELSE - ENDIF statements below as required for your application
        If cbx(sender.tag).Checked Then
            MsgBox("Check Box " & sender.tag & "  " & "Named " & sender.name & " and an Index # of " & sender.tag & " has been CHECKED")
            MsgBox("Check Box " & sender.tag & "  " & "Named " & sender.name & " and an Index # of " & sender.tag & " has been UN-CHECKED")
        End If
    End Sub

I look forward to any comments or feedback regarding this as I know this has been troubling a lot of people who are migrating from VB6 and are looking to dynamically create control arrays.

Thanks for your time and all of your previous help.

Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jeff CertainCommented:
Well, the first thing I'd do is leverage the System.Collections.Generic namespace to replace those nasty non-type-safe arrays. For example, replace Dim cbx() As CheckBox with Private cbx as New List(Of CheckBox). This gives you design-time type-checking to make sure you're only putting checkboxes in that "array". It also alleviates the need to redim, since you can simply Add/Remove the checkboxes.

I'd also consider adding a DataTable property that I set from outside the control. You'd be able to move all your database access code to a data access alyer than, and the reusability of the control would be improved, since you wouldn't be bound to a specific table in a specific database. (Or, for that matter, even a particular database type, since you can use data providers against multiple database engines to provide a datatable).

Your code looks fine.  But I've one question: why?

What you've produced is effectively a DataGrid or DataGridView with a CheckBox column and a readonly Name/Description column.  Because you don't want all the data from your datatable, some customisation of any grid would be necessary.  But I'm not sure that coding that would be any more taxing than creating your control array.  And a lot would be done for you automatically - e.g. the number of rows - and there would be the advantage (?) of databinding.

I appreciate that that may look like quibbling about the particular example you've used, rather than addressing the more basic question of whether control arrays are "a good thing".  But I do think that the answer to that basic question is more open than is sometimes assumed.  There's an awful lot of things that we were used to pre VB.NET and so which we're tempted to want to carry over.  But - with one exception, which your approach doesn't address - I'm not sure that there is anything that could be done with VB6 control arrays which cannot be done (probably as easily, once we get used to .NET ways) with VB.NET.  The exception is the design time facility of creating one control, giving it an index, and then copying it, each copy being added to the control array.

Let me stress that I am not suggesting that control arrays are "a bad thing".  But what I am suggesting is that the simple fact that we found them useful in VB6 may not, of itself, be a good enough reason for wanting to replicate them in VB.NET.  In each case, before constructing a control array in VB.NET, I would want to ask "what is it that this is going to allow me to do, or do more easily, that is not possible, or too difficult, using the facilities that are already present in VB.NET"?  And, though circumstances will alter cases and there is obviously a large element of personal choice in this, my answer would very often be "Nothing".

Jeff CertainCommented:
I just noticed that my suggestion re: generics is not applicable, since that's a VB2005 feature...
charlieb01Author Commented:

I appreciate your comments. My main reason for getting into this coding in the first place was that my company uses a core program (very large) for every piece of test equipment it sells. We are required to provide the source code and a copy of the development language (VB) to our clients. VB6 is becomming very difficult to purchase.
I have a software engineer who told me that she could not develop the core program we now have in VB6 into VB.NET - So this problem has been around for several years. Since it is a small company and we cannot afford to hire an outside contractor or another software engineer, I decided to dig out my old programming tools (that I have not used in many years) and attack the problem.
My first goal is to replicate the old VB6 core program as closely as possible so my software engineer will be able to easily follow it.
My next goal is to use what I am learning about VB.NET and apply that knowledge to developing a NEW core program with a fresher feel and look and something that will be easier to customize for each client.

But since you brought it up, I would be curious about how to develop a datagrid that is programmatically bound to a database table that could hold checkboxes and radio (or Option) buttons. My software engineer has had me purchase ComponentOne ActiveX products before for every project and I was told one of the reasons was that only TrueDBGrid could handle radio buttons or checkboxes. I would rather not spend the extra money if it is not necessary.

I appreciate any feedback.


Both the DataGrid (which is the VB.NET 2003 native grid control) and the DataGridView (which is the VB.NET 2005 grid control) have a checkbox columntype built in.  You're on 2003, so try this bit of code in a form with a datagrid on it.

    Private dt As New DataTable("TestTable")

    Private Sub filltable()
        Dim dc0 As New DataColumn("ID", GetType(Integer))
        Dim dc1 As New DataColumn("Check", GetType(Boolean))
        For i As Integer = 1 To 10
            Dim dr As DataRow = dt.NewRow
            dr(0) = i
            dr(1) = (i Mod 2 = 0)
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        DataGrid1.DataSource = dt
   End Sub

As you will see, because one of the columns in the datasource is of datatype Boolean, the datagrid automatically represents it as a checkbox.

Unfortunately, it's not quite as good as it may look at first sight, because if you click on any of the checkboxes you will see that it cycles through three states - checked, unchecked and indeterminate (grayed) - rather than just two - checked and unchecked, corresponding to true and false.  But if you're prepared to setup the datagrid with your own code, rather than just relying on the autogeneration of columns via the binding, that is easily solvable: see this link


Radio buttons are a bit more complicated.  I've never given any real though to it because I feel that, visually, more than a couple of radiobuttons in a grid might look odd; and two (or even three) states can be handled with a checkbox.  It looks like it can be done with a DataGridView in 2005: see this link


A quick Google suggests that it might be difficult in a Forms, rather than a Web, app.

One thing I would suggest is that you should try VB.NET 2005.  The Express Version is downloadable for free.  While the Express version lacks some of the bells and whistles which may be desirable in a full industrial/commercial development environment it can handle some pretty sophisticated applications even in those.  And, importantly for present purposes, the bits that were missing would not stop you trying out the development of your new core program which it sounds like you are intending to do on a single developer, rather than a team, basis.  It's DataGridView is, in my view, much easier to work with than the DataGrid.  In particular, it has an inbuilt combobox column style.  And it's that, rather than trying to develop radiobuttons, that I would use if I wanted to offer the user a restricted range of choices within a grid.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.