Recursively Finding All Controls of a specified Type via Generics

Demonstration of a static method to recursively return all controls of a specified type from an ASP.NET page.

Recently somebody on the ASP.NET forums asked how to find all the TextBoxes on a page. There were some good answers, including one using generic List<TextBox>, but my first thought was, "What if I just want a generic method that will find all of any type of control?". So without further delay, I put together this "proof of concept".

First of all, if this is something you may need to do a lot of (changing styles, properties or whatever on all the same type of control on a page) then it should probably be made a static method. In this manner you can either put it in Global.asax.cs where it is accessible from any page, or you could put the method into a static class and accomplish much the same.  So first, here's the method I came up with:

public static List<Control> GetAllControls(List<Control> controls, Type t, Control parent /* can be Page */)
        {
            foreach (Control c in parent.Controls)
            {
                if (c.GetType()== t)
                    controls.Add(c);
                if (c.HasControls())
                    controls = GetAllControls(controls, t, c);
            }
            return controls;
        }
Notice that I've declared a return type of List<Control> which allows me to return any kind of ASP.NET control. The method signature needs to accept the initial List to be populated as a parameter, since the method is called recursively. We also need to pass in the Type of the control we want to get back, and we need to specify the parent control so we'll know where to start iteration. Since the Page class derives from Control, we can pass "this" as the parent parameter.

In the sample page that proofs the concept, I have some Textboxes and some CheckBoxes. One each of the TextBox and CheckBox controls are inside a Panel control, so as to correctly illustrate the recursion.  The resulting List<Control> is bound to a GridView so we can look at the results. I also iterate over the returned collection and either populate its Text property, or if a CheckBox, I set its Checked property.  The method to perform this looks like so:
protected void Unnamed1_Click(object sender, EventArgs e)
        {
            // clear everything out first to avoid confusion:
            GridView1.DataSource = null;
            GridView1.DataBind();

            Object o = null;
            if (this.DropDownList1.SelectedValue =="TextBox")
                o = new TextBox();
            else
                o = new CheckBox();
           System.Collections.Generic.List<Control> theList =Global.GetAllControls(new List<Control>(), o.GetType(), this );
            this.GridView1.DataSource = theList;
            GridView1.DataBind();
            // do something useful to each found control...
            foreach( Control c in theList)
            {
                if (c is TextBox) ((TextBox) c).Text = "Found " + c.ID;
                if (c is CheckBox) ((CheckBox) c).Checked = true;
            }
        }
You can download the sample Visual Studio 2008 Solution here.
By Peter Bromberg   Popularity  (4622 Views)