Page 1 of 1

Control Arrays in C#

#1 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1642
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 09 March 2008 - 04:36 PM

In this tutorial we will be looking at Using a Control Array in C#. If you came to .Net from Visual Basic 6, you will remember how easy it was to work with control arrays. Well with the introduction to .Net, some of that ease has left us, due in part to the .Net languages being Object Orientated languages. But fear not my friend, it is still possible to have a control array in .Net and that is what this tutorial is for.

Back in the days of Visual Basic 6, you could simply drag multiple controls onto a form with the same name, and the language would take care of the rest for you. Unfortunately that ease has left us in .Net. This tutorial will guide you through linking your controls together in a variable, thus giving you access to their properties in a simple, succinct form. So lets dive right in adn look at how we would accomplish this.

This code is contained inside a class file, but you can move it to the Form's code-behind if you wish, though I'm not sure why you would want to. As with any class, you will need references to the proper Namespaces. Here are the Namespaces you will need to reference for this tutorial


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Text.RegularExpressions;



Since we have no properties in this class, we will let the CLR assume the empty constructor for us. With no properties to instantiate we have no need to create custom constructors for our class.

In our first method, we will be passing it the name of the form we are searching through, the control name (As you remember, a control array is a set of controls with the same naming convention, such as TextBox_1, TextBox_2,..), and the separator we are using. The separator can be whatever character you're using in your array. From there we will grab all the controls on the specified form, then loop through them looking for our specific control(s). Once we find them, we will grab the index of the first control, and the index of the last control, this will prevent an IndexOutOfBoundsException. We then add the controls, one at a time, to an ArrayList:


/// <summary>
/// Function to create a control based on the same type of control,
/// naming then TextBox1, TextBox2, TextBox3...
/// </summary>
/// <param name="frm">Form to create the control array on</param>
/// <param name="controlName">Name of the control</param>
/// <returns></returns>
/// <remarks></remarks>
public static Array MakeArray(Form frm, string controlName, string seperator)
{
    ArrayList list = new ArrayList();
    Type type = null;
    int max = -1;
    //Populate our ArrayList
    ArrayList controls = GetAllControls(frm);

    //Loop through all the controls on the specified form
    //that have the same name pattern as the name provided,
    //then find the highest indexed control
    foreach (Control control in controls)
    {
        //Get the index of the current control
        int controlIndex = control.Name.ToLower().IndexOf(controlName.ToLower() + seperator);
        //Check to see if the index is 0
        if (controlIndex == 0)
        {
            //Get the last character of the controls name
            string suffix = control.Name.Substring(controlName.Length);
            //Check to see if its an Integer 
            //(such as TextBox1, TextBox2, etc)
            if (IsNumeric(suffix))
            {
                //Find the highest index and set our 
                //variable to that value
                if (Strip(suffix) > max)
                {
                    max = Strip(suffix);
                }
            }
        }
    }

    //Make sure we have a list to work with
    if (max > -1)
    {
        //Loop through all our index values
        for (int i = 0; i <= max; i++)
        {
            //Get the control type based on the name
            Control ctrl = GetControl(controls, controlName, i);
            //Make sure the control isnt "Nothing"
            //If its not then add it to our ArrayList
            if ((ctrl != null)) type = ctrl.GetType();
            list.Add(ctrl);
        }
    }
    return list.ToArray(type);
}




The MakeArray() method is the main method in our class, it is the one that is called to retrieve our control array. You will notice, in this method we call 2 different methods; GetAllControls() and GetControl. GetAllControls() is the method we use to return all the controls on the specified form. GetAllControls() is a recursive method, meaning it calls itself until all the controls are accounted for:


/// <summary>
/// Function to retrieve all the controls on the form
/// </summary>
/// <param name="container">Control to retrieve controls from</param>
/// <returns>A populated ArrayList</returns>
/// <remarks></remarks>
public static ArrayList GetAllControls(Control container)
{
    //Create a new ArrayList object
    ArrayList list = new ArrayList();

    //Check the control, if its not the form
    //iself then we need to add it to our ArrayList
    if (!(container is Form))
    {
        list.Add(container);
    }

    //Now comes the recursive part. We check each control,
    //if it has children (say its a GroupBox with controls in it)
    //then this calls itself until all controls are accounted for

    //Check to see if the control has children controls
    if (container.HasChildren)
    {
        //If it does then we loop through all those controls
        foreach (Control control in container.Controls)
        {
            //Create a new ArrayList for all the "sub controls"
            //located within the control
            ArrayList subControls = GetAllControls(control);
            //Add the sub controls list to our ArrayList
            list.AddRange(subControls);
        }
    }
    //Return the ArrayList
    return list;
}




The GetControl() method is used to retrieve a specific control using it's name. Here we will pass in the ArrayList that holds our controls, the name of the control we're looking for, and the index of the control. The method will then return the control we have requested, so it can be added to the array:


/// <summary>
/// Function to retrieve a control by
/// A) Name
/// B)/> Index in the provided ArrayList
/// </summary>
/// <param name="ctrlList">ArrayList of controls</param>
/// <param name="name">Name of the control we're looking for</param>
/// <param name="index">The controls index in the array</param>
/// <returns>A control</returns>
/// <remarks></remarks>
private static Control GetControl(ArrayList list, string controlName, int listIndex)
{
    //Set the Controls name (in the format Control1, Control2, Control3,...)
    controlName = controlName + listIndex;
    //Make sure we dont hve an empty ArrayList
    if ((list != null))
    {
        //Loop through all the controls in the list
        foreach (Control control in list)
        {
            //Check the name passed in with the one
            //for the control at this index
            //If it matches then return the control
            if (string.Compare(control.Name, controlName, true) == 0)
            {
                return control;
            }
        }
    }
    //Otherwise return Nothing as the control
    //couldn't be found
    return null;
}




In this class, I offer a 2nd way of returning a control array, as opposed to the first option which returns an ArrayList populated with our controls. The GetControlArray() actually returns a Control[] array, much different then the first option, which returns an ArrayList. As with the MakeArray(), we must provide the Form we are searching, the name of the control we want, and the seperator being used in the name:


/// <summary>
/// Creates a control array (any type control) with controls that have the same name pattern
/// such as Control_1, Control_2...
/// </summary>
/// <param name="frm">Form the search for controls on</param>
/// <param name="controlName">Name of the control</param>
/// <returns></returns>
/// <remarks></remarks>
public static Control[] GetControlArray(Form frm, string controlName,string seperator)
{
    ArrayList list = new ArrayList();
    int max = -1;
    //Populate our ArrayList
    ArrayList controls = GetAllControls(frm);

    //Loop through all the controls on the specified form
    //that have the same name pattern as the name provided,
    //then find the highest indexed control
    foreach (Control ctl in controls)
    {
        //Get the index of the current control
        int start = ctl.Name.ToLower().IndexOf(controlName.ToLower() + seperator);
        //Check to see if the index is 0
        if (start == 0)
        {
            string suffix = ctl.Name.Substring(controlName.Length);
            //Check to see if its an Integer 
            //(such as TextBox1, TextBox2, etc)
            if (IsNumeric(suffix))
            {
                //Find the highest index and set our 
                //variable to that value
                if (Strip(suffix) > max)
                {
                    max = Strip(suffix);
                }
            }
        }
    }

    //Make sure we have a list to work with
    if (max > -1)
    {
        //Loop through all our index values
        for (int i = 0; i <= max; i++)
        {
            //Get the control and add it to our ArrayList
            Control ctrl = GetControl(controls, controlName, i);
            list.Add(ctrl);
        }
    }
    return (Control[])list.ToArray(typeof(Control));
}



In the GetControlArray() and MakeArray() method's we reference 2 more methods, IsNumberic and Strip, the IsNumeric method checks the provided value to see if it's numeric, and the Strip method is designed to mimic the Val() function in legacy Visual Basic. First the IsNumeric method:


/// <summary>
/// Function to check if a value is numeric. 
/// </summary>
/// <param name="value">Value to check</param>
/// <returns>True/False</returns>
/// <remarks>
/// I chose to go with my own function as there are times when 
/// the built in IsNumeric returns false positives and vicea versa
///</remarks>
private static bool IsNumeric(string value)
{
    //First make sure a value was provided
    if (!(value == string.Empty))
    {
        //Now we will loop through each char in the string
        foreach (char character in value)
        {
            //If TryParse failes we will return False as it
            //is not a numeric value
            int temp;
            if (!(int.TryParse(character.ToString(), out temp)))
            {
                return false;
            }
            else
            {
                //Otherwise we return True
                return true;
            }
        }
    }
    else
    {
        //Return False because no value was provided
        return false;
    }
    return true;
}



Here we use the TryParse Method to check if the value provided is a numeric value, if it is we return true, otherwise we return false. The Strip() method we use the MatchCollection Class of the System.Text.RegularExpressions Namespace to hold each character that matches our pattern:


/// <summary>
/// Function to mimic the Val() function in legacy VB. 
/// </summary>
/// <param name="str">String we want the numeric values from</param>
/// <returns>Integer</returns>
/// <remarks>
/// I chose to go with my own functions because I didnt want to use 
/// legacy libraries and there really isnt an intrinsic method in
/// VB.Net to mimic the Val() function
///</remarks>
private static int Strip(string value)
{
    string val = "";
    MatchCollection collection = Regex.Matches(value, "\\d+");
    foreach (Match match in collection)
    {
        val += value;
    }
    return Convert.ToInt32(val);
}




There you have it, the basis for working with a Control Array in C#. I will now provide a couple examples on how to implement this into your application.

Lets say on your form you have multiple TextBoxes with the same naming convention you're using as a control array, for example


Quote

TextBox_1, TextBox_2, TextBox_3, ... TextBox_n


You could create an control array of TextBoxes, providing the Form to which you want to search, the name of the controls, and the separator, in this example it's "_". That would look like:


//here we will create our control array when the form loads,
//then we will set the text property of each textbox to the
//value of a counter
private void Form1_Load(object sender, System.EventArgs e)
{
       //create our control array
	TextBox[] tb = GetControlArray(this,"TextBox","_");
       //now loop through our control array to set the text of
       //each textbox to the value in our counter
	for (int i = 1; i <= tb.Length(); i++) 
        {
		tb(i).Text = i.ToString();
	}
}




So that is how you can work with a control array in C#. Below is the class file in it's entirety, I hope you found this tutorial informative and useful, and I thank you for reading :)


//*****************************************************************************************
//                           LICENSE INFORMATION
//*****************************************************************************************
//   PCControlArray Version 1.0.0.0
//   Utility class file for creating and working with control arrays in C#
//
//   Copyright © 2007  
//   Richard L. McCutchen 
//   Email: psychocoder@dreamincode.net
//   Created: 14SEP07
//
//   This program is free software: you can redistribute it and/or modify
//   it under the terms of the GNU General Public License as published by
//   the Free Software Foundation, either version 3 of the License, or
//   (at your option) any later version.
//
//   This program is distributed in the hope that it will be useful,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program.  If not, see <http://www.gnu.org/licenses/>.
//*****************************************************************************************


using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Text.RegularExpressions;

namespace PC
{
    public class ControlArray
    {
        /// <summary>
        /// Function to create a control based on the same type of control,
        /// naming then TextBox1, TextBox2, TextBox3...
        /// </summary>
        /// <param name="frm">Form to create the control array on</param>
        /// <param name="controlName">Name of the control</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static Array MakeArray(Form frm, string controlName, string seperator)
        {
            ArrayList list = new ArrayList();
            Type type = null;
            int max = -1;
            //Populate our ArrayList
            ArrayList controls = GetAllControls(frm);

            //Loop through all the controls on the specified form
            //that have the same name pattern as the name provided,
            //then find the highest indexed control
            foreach (Control control in controls)
            {
                //Get the index of the current control
                int controlIndex = control.Name.ToLower().IndexOf(controlName.ToLower() + seperator);
                //Check to see if the index is 0
                if (controlIndex == 0)
                {
                    //Get the last character of the controls name
                    string suffix = control.Name.Substring(controlName.Length);
                    //Check to see if its an Integer 
                    //(such as TextBox1, TextBox2, etc)
                    if (IsNumeric(suffix))
                    {
                        //Find the highest index and set our 
                        //variable to that value
                        if (Strip(suffix) > max)
                        {
                            max = Strip(suffix);
                        }
                    }
                }
            }

            //Make sure we have a list to work with
            if (max > -1)
            {
                //Loop through all our index values
                for (int i = 0; i <= max; i++)
                {
                    //Get the control type based on the name
                    Control ctrl = GetControl(controls, controlName, i);
                    //Make sure the control isnt "Nothing"
                    //If its not then add it to our ArrayList
                    if ((ctrl != null)) type = ctrl.GetType();
                    list.Add(ctrl);
                }
            }
            return list.ToArray(type);
        }


        /// <summary>
        /// Function to retrieve all the controls on the form
        /// </summary>
        /// <param name="container">Control to retrieve controls from</param>
        /// <returns>A populated ArrayList</returns>
        /// <remarks></remarks>
        public static ArrayList GetAllControls(Control container)
        {
            //Create a new ArrayList object
            ArrayList list = new ArrayList();

            //Check the control, if its not the form
            //iself then we need to add it to our ArrayList
            if (!(container is Form))
            {
                list.Add(container);
            }

            //Now comes the recursive part. We check each control,
            //if it has children (say its a GroupBox with controls in it)
            //then this calls itself until all controls are accounted for

            //Check to see if the control has children controls
            if (container.HasChildren)
            {
                //If it does then we loop through all those controls
                foreach (Control control in container.Controls)
                {
                    //Create a new ArrayList for all the "sub controls"
                    //located within the control
                    ArrayList subControls = GetAllControls(control);
                    //Add the sub controls list to our ArrayList
                    list.AddRange(subControls);
                }
            }
            //Return the ArrayList
            return list;
        }

        /// <summary>
        /// Creates a control array (any type control) with controls that have the same name pattern
        /// such as Control_1, Control_2...
        /// </summary>
        /// <param name="frm">Form the search for controls on</param>
        /// <param name="controlName">Name of the control</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static Control[] GetControlArray(Form frm, string controlName,string seperator)
        {
            ArrayList list = new ArrayList();
            int max = -1;
            //Populate our ArrayList
            ArrayList controls = GetAllControls(frm);

            //Loop through all the controls on the specified form
            //that have the same name pattern as the name provided,
            //then find the highest indexed control
            foreach (Control ctl in controls)
            {
                //Get the index of the current control
                int start = ctl.Name.ToLower().IndexOf(controlName.ToLower() + seperator);
                //Check to see if the index is 0
                if (start == 0)
                {
                    string suffix = ctl.Name.Substring(controlName.Length);
                    //Check to see if its an Integer 
                    //(such as TextBox1, TextBox2, etc)
                    if (IsNumeric(suffix))
                    {
                        //Find the highest index and set our 
                        //variable to that value
                        if (Strip(suffix) > max)
                        {
                            max = Strip(suffix);
                        }
                    }
                }
            }

            //Make sure we have a list to work with
            if (max > -1)
            {
                //Loop through all our index values
                for (int i = 0; i <= max; i++)
                {
                    //Get the control and add it to our ArrayList
                    Control ctrl = GetControl(controls, controlName, i);
                    list.Add(ctrl);
                }
            }
            return (Control[])list.ToArray(typeof(Control));
        }

        /// <summary>
        /// Function to retrieve a control by
        /// A) Name
        /// B)/> Index in the provided ArrayList
        /// </summary>
        /// <param name="ctrlList">ArrayList of controls</param>
        /// <param name="name">Name of the control we're looking for</param>
        /// <param name="index">The controls index in the array</param>
        /// <returns>A control</returns>
        /// <remarks></remarks>
        private static Control GetControl(ArrayList list, string controlName, int listIndex)
        {
            //Set the Controls name (in the format Control1, Control2, Control3,...)
            controlName = controlName + listIndex;
            //Make sure we dont hve an empty ArrayList
            if ((list != null))
            {
                //Loop through all the controls in the list
                foreach (Control control in list)
                {
                    //Check the name passed in with the one
                    //for the control at this index
                    //If it matches then return the control
                    if (string.Compare(control.Name, controlName, true) == 0)
                    {
                        return control;
                    }
                }
            }
            //Otherwise return Nothing as the control
            //couldn't be found
            return null;
        }

        /// <summary>
        /// Function to check if a value is numeric. 
        /// </summary>
        /// <param name="value">Value to check</param>
        /// <returns>True/False</returns>
        /// <remarks>
        /// I chose to go with my own function as there are times when 
        /// the built in IsNumeric returns false positives and vicea versa
        ///</remarks>
        private static bool IsNumeric(string value)
        {
            //First make sure a value was provided
            if (!(value == string.Empty))
            {
                //Now we will loop through each char in the string
                foreach (char character in value)
                {
                    //If TryParse failes we will return False as it
                    //is not a numeric value
                    int temp;
                    if (!(int.TryParse(character.ToString(), out temp)))
                    {
                        return false;
                    }
                    else
                    {
                        //Otherwise we return True
                        return true;
                    }
                }
            }
            else
            {
                //Return False because no value was provided
                return false;
            }
            return true;
        }

        /// <summary>
        /// Function to mimic the Val() function in legacy VB. 
        /// </summary>
        /// <param name="str">String we want the numeric values from</param>
        /// <returns>Integer</returns>
        /// <remarks>
        /// I chose to go with my own functions because I didnt want to use 
        /// legacy libraries and there really isnt an intrinsic method in
        /// VB.Net to mimic the Val() function
        ///</remarks>
        private static int Strip(string value)
        {
            string val = "";
            MatchCollection collection = Regex.Matches(value, "\\d+");
            foreach (Match match in collection)
            {
                val += value;
            }
            return Convert.ToInt32(val);
        }
    }
}




Happy Coding!

Is This A Good Question/Topic? 0
  • +

Replies To: Control Arrays in C#

#2 Jayman  Icon User is offline

  • Student of Life
  • member icon

Reputation: 418
  • View blog
  • Posts: 9,532
  • Joined: 26-December 05

Posted 09 March 2008 - 05:08 PM

Very well written, Richard. Makes for an excellent read. Keep up the good work!
Was This Post Helpful? 0
  • +
  • -

#3 PsychoCoder  Icon User is offline

  • Google.Sucks.Init(true);
  • member icon

Reputation: 1642
  • View blog
  • Posts: 19,853
  • Joined: 26-July 07

Posted 09 March 2008 - 05:15 PM

Thank you Jay :) I just try to help as much as I can
Was This Post Helpful? 0
  • +
  • -

#4 papuccino1  Icon User is offline

  • His name was Robert Paulson.
  • member icon

Reputation: 63
  • View blog
  • Posts: 1,121
  • Joined: 02-March 08

Posted 09 March 2008 - 05:54 PM

View PostPsychoCoder, on 9 Mar, 2008 - 05:15 PM, said:

Thank you Jay :) I just try to help as much as I can



Hey this is what I used for my Bingo game :) I'll have to read this ASAP to get a better feel for it. Great work. :D
Was This Post Helpful? 0
  • +
  • -

#5 mlkeeney  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 08-November 09

Posted 08 November 2009 - 10:09 AM

When I try to implement the following line:
TextBox[] tb = GetControlArray(this, "TextBox", "_");

I get the following error:
Cannot implicitly convert type 'System.Windows.Forms.Control[]' to 'System.Windows.Forms.TextBox[]'.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1