Brendan Enrick

Daily Software Development

Generic Recursive Find Control Extension

Earlier today I posted about a Recursive Find Control Extension Method. Since then, I was informed by Steve Smith that I should check out the generic find control method which Aaron Robson has on his blog. He has some pretty nice methods there, so I just adapted them to be extension methods now. As extension methods the code looks like this.

/// <summary>
/// Similar to Control.FindControl, but recurses through child controls.
/// </summary>
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
    T found = startingControl.FindControl(id) as T;
 
    if (found == null)
    {
        found = FindChildControl<T>(startingControl, id);
    }
 
    return found;
}
 
/// <summary>     
/// Similar to Control.FindControl, but recurses through child controls.
/// Assumes that startingControl is NOT the control you are searching for.
/// </summary>
public static T FindChildControl<T>(this Control startingControl, string id) where T : Control
{
    T found = null;
 
    foreach (Control activeControl in startingControl.Controls)
    {
        found = activeControl as T;
 
        if (found == null || (string.Compare(id, found.ID, true) != 0))
        {
            found = FindChildControl<T>(activeControl, id);
        }
 
        if (found != null)
        {
            break;
        }
    }
 
    return found;
}

And this new extension method is called very similarly to how we called the previous code. It is called using the following code.

Label theOtherLabel = LoginView1.FindControl<Label>("OtherControlToFind");
if (theOtherLabel != null)
{
    theOtherLabel.Text = "Found this one also!";
}

It is able to find the Label inside of the the following LoginView.

<asp:LoginView ID="LoginView1" runat="server">
    <LoggedInTemplate>
        <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" Style="color: Red" />
                            <asp:Label ID="OtherControlToFind" runat="server" Style="color: Blue" />
                            <asp:Label ID="AlwaysShow" runat="server" Text="This shows no matter what." />
                        </asp:Panel>
                    </asp:Panel>
                </asp:Panel>
            </asp:Panel>
        </asp:Panel>
    </LoggedInTemplate>
</asp:LoginView>

I've also updated my FindControl method so that is just an overload of the previous method. Since my extension method takes the same parameters and returns the same type as the existing find control method I needed to rename it FindControlR. I've now updated it so it takes an extra parameter, but doesn't have a different name. I've added a boolean "recurse" parameter. If this is set to false it just calls the standard FindControl method and if it is set to true it will recursively call itself finding the desired control.

This is the final product followed by how one would call it.

/// <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 FindControl(this Control root, string id, bool recurse)
{
    if (!recurse)
    {
        return root.FindControl(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.FindControl(id, true);
            if (controlFound != null)
            {
                return controlFound;
            }
        } 
    } 
    return null;
}
Label theLabel = LoginView1.FindControl("ControlToFind", true) as Label;
if (theLabel != null)
{
    theLabel.Text = "Found it!";
}

I hope everyone else sees the great value in extension methods.

Loading