Creating a Recursive FindControl Extension Method

So one of the most useful methods for ASP.NET development that never seems to be included in ASP.NET is a recursive find control method. This problem results from the standard FindControl method on controls only searching within that control. It only finds child controls not grandchildren or anything farther down the line. This means that anything nested within other controls is a pain to access.

This limitation of the standard FindControl is annoying and has prompted me as well as many other people to use homegrown FindControl methods to solve this problem. This is a big problem when trying to programmatically access controls within templates. So earlier today I read on a list someone having trouble with the built-in find control, and it made me thing that a recursive find control would make a great extension method since it is a method plenty of people want to see on the control class anyway. So I went and wrote this simple little extension method.

For this nifty example I'll use this as my Page class. I've nested some Panels here to make sure that a standard find control would not work.

<form id="form1" runat="server">
<div>
    <asp:Panel ID="Panel1" runat="server">
        <asp:Panel ID="Panel2" runat="server">
            <asp:Panel ID="Panel3" runat="server">
                <asp:Panel ID="Panel4" runat="server">
                    <asp:Panel ID="Panel5" runat="server">
                        <asp:Label ID="ControlToFind" runat="server" />
                    </asp:Panel>
                </asp:Panel>
            </asp:Panel>
        </asp:Panel>
    </asp:Panel>
</div>
</form>

Now you'll see here in the code behind I am calling my recursive find control extension method. Notice that I am checking for null afterwards. This is because if I do not find the control my method returns null, so I should check for this. Also because I am using the as statement if the control is not a label my variable will also be null.

protected void Page_Load(object sender, EventArgs e)
{
    Label theLabel = form1.FindControlR("ControlToFind") as Label;
    if (theLabel != null)
    {
        theLabel.Text = "Found it!";
    }
}

Here is the code which makes this cool extension method possible.

public static class Extensions
{
    /// <summary>
    /// Searches recursively in this control to find a control with the name specified.
    /// </summary>
    /// <param name="root">The Control in which to begin searching.</param>
    /// <param name="id">The ID of the control to be found.</param>
    /// <returns>The control if it is found or null if it is not.</returns>
    public static Control FindControlR(this Control root, string id)
    {
        System.Web.UI.Control controlFound; 
        if (root != null) 
        { 
            controlFound = root.FindControl(id);
            if (controlFound != null)
            {
                return controlFound;
            }
            foreach (Control c in root.Controls) 
            {
                controlFound = c.FindControlR(id);
                if (controlFound != null)
                {
                    return controlFound;
                }
            } 
        } 
        return null;
    }
}

To create an extension method all I need to do is create a static method in a static class and pass as a parameter "this Type name" where Type and name are the type we wish to extend and name is a local variable name for the instance with which we wish to interact.

One thing I don't see in many examples of extension methods which I have used here is passing a parameter in the extension method. It really is this simple to pass the extra parameter.

This syntax reminds me a lot of the python language whose non-static class methods accept "this" as a parameter. It defines them as taking the instance as a parameter.

Have a great day!

Comments