Results 1 to 23 of 23

Thread: Control Arrays in VB.NET

Threaded View

  1. #1

    Thread Starter
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Control Arrays in VB.NET

    If you're like me and you started coding in VB.NET (or C#, or probably any other programming language) without ever having coded in VB6 then you've probably never felt the need for a control array, at least in the VB6 sense. To hear many migrating VB6 developers tell it though, VB6 control arrays are the greatest programming invention ever and living without them in VB.NET is nigh on unbearable.

    The thing is, design-time support for control arrays was added to VB6 for a reason: to enable the same event to be handled for multiple controls with a single method. In VB.NET, you can do that simply by adding multiple controls to the Handles clause of a method. As such, design-time support for control arrays is not needed in VB.NET, so it was never added. Take away the need for handling events for multiple controls and control arrays are exactly like any other arrays, which is exactly how they are treated in VB.NET and all other .NET languages.

    VB6 developers often contend that creating a control array in the designer is sooooo much more convenient than doing so in code. I don't necessarily disagree that it could be more convenient but I probably do disagree with how much more. With Intellisense you can generally create an array of controls in code in less than a minute, if not in seconds. If the array should contain a very large number of controls then you can always use a loop and get each control from the form's Controls collection by name. It's really not a big deal.

    Anyway, rather than fight it any longer I decided to create something that would help these poor souls. I know that various people have posted various such things around the place. I haven't checked any of those out so I don't know they compare to this current implementation. I've also never used VB6 so I don't know exactly how this compares to how control arrays work in VB6. What I do know is that this current implementation allows you to set the Index property of a control in the designer to add it to a collection that you can access in code, either using a For Each loop or accessing a specific control by index.

    So, the first order of business is design-time support. In order to be able to add something to the Toolbox in VS, it must implement the IComponent interface. You can implement IComponent yourself, but the more usual way is to inherit the Component class. As such, that was the first thing to do here:
    vb.net Code:
    1. Public Class ControlArray
    2.     Inherits System.ComponentModel.Component
    3. End Class
    The next thing to do is to provide the Index property on each control. If you've ever used a ToolTip, you know that this can be done, although you may not know how. The secret is the IExtenderProvider interface, along with a few associated tricks. To implement the interface, you must define the CanExtend method. This method takes an object and returns a Boolean that indicates whether the object can be extended or not:
    vb.net Code:
    1. Public Class ControlArray
    2.     Inherits System.ComponentModel.Component
    3.     Implements System.ComponentModel.IExtenderProvider
    4.  
    5.     Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend
    6.         Return TypeOf extendee Is Control
    7.     End Function
    8.  
    9. End Class
    That's not enough on its own though. There's two more elements required to make this class useful. First, we need to specify exactly what property eligible controls will extended with. After that, we need to actually provide an implementation for that property. A property is just a convenient way to package together two methods: one that gets a value and one that sets a value. In this case, we implement those as just regular methods:
    vb.net Code:
    1. <System.ComponentModel.ProvideProperty("Index", GetType(Control))>
    2. Public Class ControlArray
    3.     Inherits System.ComponentModel.Component
    4.     Implements System.ComponentModel.IExtenderProvider
    5.  
    6.     Private controls As New List(Of Control)
    7.  
    8.     Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend
    9.         Return TypeOf extendee Is Control
    10.     End Function
    11.  
    12.     Public Function GetIndex(ByVal control As System.Windows.Forms.Control) As Integer
    13.         Return Me.controls.IndexOf(control)
    14.     End Function
    15.  
    16.     Public Sub SetIndex(ByVal control As Control, ByVal index As Integer)
    17.         Me.controls.Insert(index, control)
    18.     End Sub
    19.  
    20. End Class
    The final step is to expose the internal collection so that it can be used in code:
    vb.net Code:
    1. <System.ComponentModel.ProvideProperty("Index", GetType(Control))>
    2. Public Class ControlArray
    3.     Inherits System.ComponentModel.Component
    4.     Implements System.ComponentModel.IExtenderProvider
    5.  
    6.     Private _controls As New List(Of Control)
    7.  
    8.     Public ReadOnly Property Controls As List(Of Control)
    9.         Get
    10.             Return Me._controls
    11.         End Get
    12.     End Property
    13.  
    14.     Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend
    15.         Return TypeOf extendee Is Control
    16.     End Function
    17.  
    18.     Public Function GetIndex(ByVal control As System.Windows.Forms.Control) As Integer
    19.         Return Me.controls.IndexOf(control)
    20.     End Function
    21.  
    22.     Public Sub SetIndex(ByVal control As Control, ByVal index As Integer)
    23.         Me.controls.Insert(index, control)
    24.     End Sub
    25.  
    26. End Class
    That's all the basics in place, but that implementation won't do it. The attached solution includes a much more rigorous implementation that addresses these issues. The ControlArray class included in that solution is actually a base class only, with various derived classes provided for various specific types of controls. The sample application includes a form that contains a ButtonArray and a TextBoxArray. When you run the project, you'll be shown each item in the collection.

    In the designer, you can select a Button or a TextBox and you'll find an extra Index property at the bottom of the Properties window. Clearing the property will remove the control from the collection and setting it will add the control to the collection. Note that adding and removing controls will automatically adjust the Indexes of all other controls in the collection. Note also that you can set the Index of a control to a value beyond the size of the collection and it will automatically adjust to add the control to the end of the collection. A very interesting feature of this auto-adjusting behaviour is that you can select multiple controls in the designer and then set the index property to a single value for all of them and they will all be added to the collection with distinct Index values.

    A further feature of the attached sample is an extended derived class for the RadioButton control. Any and all methods of the base class that add or remove items in the collection have been declared Overridable. This means that you can override all those members and provide extra processing when items are added and removed. The RadioButtonArray class provided adds and removes a handler on the CheckedChanged event of each item in the collection that will uncheck every other item when one RadioButton is checked. This may sound redundant as it's the default behaviour of RadioButton's anyway, but in this case the behaviour is independent of container. This means that RadioButtons in different containers can all act as a single group. The sample contains three groups of three RadioButtons contained in different Panels to demonstrate this.

    Finally, the attached solution was created in VS 2010 so will only be able to be opened in VS 2010 or VB Express 2010. You can add the ControlArray.vb code file to any project in VB 2005 or later though. The one change that might be required is the addition of a few line continuation characters.
    Attached Files Attached Files
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width