Finding Controls on Forms

Posted Mon, Jul 27 2009 10:43 by Deborah Kurata

There are often times that you need to find specific controls on a Windows Form (WinForm). For example, you may want to find all of the TextBoxes to clear their contents, set their background color, or hook up events. You may want to find all of the checkboxes to check or uncheck them. Or find all of the buttons to hook up events or change their color.

Since a Windows Form has a Controls collection, it may seem obvious to simply loop through the Control's collection to find all of the desired controls.

But many of the controls provided in WinForms can contain other controls. Take this form for example:

image

This form contains two Panel controls. The top Panel control contains several Label controls and a ComboBox. The bottom Panel control contains Labels and TextBoxes.

If you look at the Controls collection for the form in this example, you find that it contains only two controls. Only the two Panel controls are actually on the form. The other controls are on the Panel controls. So to find those controls, you need to loop through the Controls collection of each Panel.

If you put a Tab control on a Panel control, then the TextBox controls would be on the Tab control which is on the Panel control. The easiest way to look for controls that could be on other controls which in turn could be on other controls, is to use recursion.

Recursion is basically calling a method from the method itself. (You can find a more detailed explanation here.) The following demonstrates recursion to find all of the TextBoxes on a form.

In C#:

private void ProcessControls(Control ctrlContainer)
{
    foreach (Control ctrl in ctrlContainer.Controls)
    {
        if (ctrl.GetType() == typeof(TextBox))
        {
            // Do whatever to the TextBox
        }

        if (ctrl.HasChildren)
            ProcessControls(ctrl);
    }
}

In VB:

Private Sub ProcessControls(ByVal ctrlContainer As Control)
    For Each ctrl As Control In ctrlContainer.Controls
        If TypeOf ctrl Is TextBox Then
            ' Do whatever to the TextBox
        End If

        ' If the control has children,
        ' recursively call this function
        If ctrl.HasChildren Then
            ProcessControls(ctrl)
        End If
    Next
End Sub

The code begins by processing each control within the defined container control using the container’s Controls collection. The control’s type is checked to determine if it is the desired type of control. This technique can be used to look for any type of control or multiple types of controls.

The HasChildren property of the control is checked to determine if the control itself is a container for other controls. If so, it calls this method recursively using the control as the container control.

This method resides in the Form and is called as follows.

In C#:

ProcessControls(this);

In VB:

ProcessControls(Me)

The form itself is passed into the ProcessControls method as the highest level container. If you only want to search for controls within some other container, pass it instead of the entire form. For example, if you only wanted to search for TextBox controls on Panel2 or on controls that are on Panel2, you would pass Panel2 instead of the form (this or me).

Finding Controls By Name

If you want to find a control or set of controls by name, there is an easier way.

In C#:

Control[] ctrls = this.Controls.Find("TextBox1", true);

In VB:

Dim ctrls() As Control = Me.Controls.Find("TextBox1", True)

This code uses the Find method of the controls collection. The first parameter defines the name of the control(s) to find. If the second parameter is true, the Find will search through all child controls, performing the recursive operation for you. If it is false, it will only look through the form’s Controls collection.

When I was first working with the Find method, I thought it odd that it returned an array since you can only put one control on the form named “TextBox1”. However, you can add multiple controls with the same name using Controls.Add. Also, if you build a composite user control you can also put a TextBox1 on the user control. So if you also have a TextBox1 on the form, the Find method will find two controls named “TextBox1”.

Enjoy!

Filed under: , , , ,

Comments

# re: Finding Controls on Forms

Monday, July 27, 2009 7:33 PM by James Arendt

Debora, your articles hit that sweet spot for those looking at "how to do stuff" with .NET. Straight to the point, easy to understand. Having examples in both VB and C# is also a rarity and greatly appreciated.

The C# code example in this article could be improved, though. If you're using GetType() and typeof, there's no need to then do a .Name to do the comparison. You can use the == operator to do a direct comparison between the two type objects.

With that said, I personally would probably use the is or as operator in C# for the check unless I only wanted TextBox objects. Those operators will match a TextBox or anything that derives from TextBox. The comparison with GetType and typeof will only match a TextBox object.

Lastly, if the code is intended to work with any type of "textbox" (ex. TextBox, MaskedTextBox) in the processing, keying off of the TextBoxBase class would allow that.

# re: Finding Controls on Forms

Tuesday, July 28, 2009 10:05 AM by Deborah Kurata

Hi James -

Thank you for your kind comments about the blog and for your tips. I will remove the .Name property as per your suggestion. Thanks again!

# re: Finding Controls on Forms

Wednesday, July 29, 2009 11:01 AM by Ruddy

This was a great tip. I tried to do this in a web form and it was a really ugly solution with tons of if statements (Controls were in a master page) This is much cleaner and nicer

I love your blog!!

# re: Finding Controls on Forms

Wednesday, August 12, 2009 11:00 AM by LotusShiv

Debora,

 Only thing is for ASP.Net replace the HasChildren with HasControls(), in the above Process.... function, there you have it for ASP.Net application environment as well.

I have one such recursive function where in I had to set the checkboxes within a HtmlTable control on a aspx page. So to this function I pass the list of checkbox values and the HtmlTable control. I then check if the current control is a HtmlInputCheckbox and if so, set the checkbox state (checked) if the value of it is one among the list that I have passed as input. Here is the code

       /// <summary>
       ///   Recursive function to set the Checkbox controls within the container control.
       /// </summary>
       /// <param name="listArray"></param>
       /// <param name="ctrlContainer"></param>
       /// <param name="listIndex"></param>
       public static void ProcessCheckboxControls(string[] listArray, Control ctrlContainer, int listIndex)
       {
           HtmlInputCheckBox checkBox = null;
           foreach (Control ctrl in ctrlContainer.Controls)
           {
               if (ctrl.GetType() == typeof(HtmlInputCheckBox))
               {
                   //First initialize the checkbox
                   ((HtmlInputCheckBox)ctrl).Checked = false;

                   //Now set the checked status from the list (if applicable)
                   SetCheckboxFromList(listArray, (HtmlInputCheckBox)ctrl);
                   listIndex++;
                   return;
               }

               if (ctrl.HasControls())
                   ProcessCheckboxControls(listArray, ctrl, listIndex);
           }

       }

       /// <summary>
       ///   Set checkbox from List.
       /// </summary>
       /// <param name="listArray"></param>
       /// <param name="checkBox"></param>
       public static void SetCheckboxFromList(string[] listArray, HtmlInputCheckBox checkBox)
       {
           int i = 0;
           for (i = 0; i < listArray.Length; i++)
           {
               //Check to see if the checkbox value matches with any of the listArray items
               if (checkBox.Value == listArray)
               {
                   checkBox.Checked = true;
                   break;
               }
           }
       }

Thanks

# re: Finding Controls on Forms

Wednesday, August 12, 2009 12:36 PM by Deborah Kurata

Hi LotusShiv -

Thank you for your comment and associated code for use with ASP.NET. Great example!

NOTE: I removed some of the excess blank space between the lines for space reasons. I did not reformat any wrapped lines, however.

Thanks again!

# re: Finding Controls on Forms

Sunday, December 20, 2009 1:09 PM by Roger

Good, thorough and useful explanation.

Especially glad you included mention of how the

Find method can return more than one control with

same name.

Roger

# re: Finding Controls on Forms

Monday, December 28, 2009 2:30 PM by Bon Maraneta

This really helps me a lot specially for a newbie like me in .net

# Display my editable form as read-only

Tuesday, January 19, 2010 9:56 AM by anamika

I had the need to make my web form display in a non editable fashion in a certain situation. Thanks for your code. I modified it and used it to loop through all the controls to make them disabled.

Method code:

private void ProcessControls(Control ctrlContainer)
       {
           foreach (Control ctrl in ctrlContainer.Controls)
           {
               if (ctrl.GetType() == typeof(TextBox))
               {
                     ((TextBox)ctrl).ReadOnly = true; 
                }

               if (ctrl.GetType() == typeof(DropDownList))
               {
                   ((DropDownList)ctrl).Enabled = false;
               }

               if (ctrl.GetType() == typeof(Button))
               {
                   ((Button)ctrl).Enabled = false;
               }                

               // if a control contains sub controls, they will be disabled by this recursive call
               if (ctrl.HasControls())
                   ProcessControls(ctrl);
           }
       }

I called this from Page_Load like you mentioned:

ProcessControl(this).

Thanks once again. Just wanted to record it here that this solution will work for disabling all controls in a page if you needed them to be view only.

# re: Finding Controls on Forms

Thursday, May 20, 2010 3:13 AM by Kundan Singh Chouhan

Awsome work dude...

Leave a Comment

(required) 
(required) 
(optional)
(required) 
If you can't read this number refresh your screen
Enter the numbers above: