Search code examples
c#asp.netweb-controlsdynamicfindcontrol

Trouble with FindControl and dynamicly created controls


Example code:

    var div = new HtmlGenericControl("div");
    div.Controls.Add(new Literal() { ID = "litSomeLit" });
    var lit = (Literal)div.FindControl("litSomeLit");
    Assert.IsNotNull(lit);

This code fails the assert, because lit is null. Debugging shows that div.Controls definitely contains a literal with ID of "litSomeLit." My questions are "Why?" and "Is there any way to get a control of a specific ID without doing a recursive search of div.Controls[] by hand one element at a time?"

The reason I'm doing things this way is that my actual application is not so straightforward- a method I'm writing is given a complex control with several subcontrols in a number of possible configurations. I need to access a specific control several layers down (eg, the control with ID "txtSpecificControl" might be at StartingControl.Controls[0].Controls[2].Controls[1].Controls[3]). Normally I could just do FindControl("txtSpecificControl"), but that does not seem to work when the controls were just dynamically created (as in the above example code).


Solution

  • Near as I can tell, there is no way to do what I'm trying to accomplish without adding the control to the page. If I had to guess, I'd say that FindControl uses the UniqueID property of the control, which generally contains the IDs of all the controls above the current one (eg OuterControlID$LowerControlId$TargetControlID). That would only get generated when the control actually gets added to the page.

    Anyway, here's an implementation of recursive depth-first-search FindControl that'll work when the control is not attached to the page yet:

        public static Control FindControl(Control parent, string id)
        {
            foreach (Control control in parent.Controls)
            {
                if (control.ID == id)
                {
                    return control;
                }
                var childResult = FindControl(control, id);
                if (childResult != null)
                {
                    return childResult;
                }
            }
            return null;
        }