views:

56

answers:

3

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).

A: 

When you confirmed that the control was in the Controls collection, did you do that by inspecting the collection directly? FindControl() may not work in this context.

When you debug the test, is the var lit null? If so, you may have to access the member by item index instead of using the FindControl() method.

Dave Swersky
A) Yes, by inspecting the control's Controls collection. However, the following test passes just fine: http://snipt.net/fishtoaster/findcontrol/ which would imply that FindControl should be able to find it.B) Err, yes. That's the whole point of the question- why is it null, and/or how can I get around that fact without having to go through and access everything by item index (which would be tedious, since I don't know exactly how deep and at what index my target control is)?
Fishtoaster
+2  A: 

Change your code to

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

As far as i know FindControl only works when the control is in the visual tree of the page.

Vinay B R
I can't make that change, since my method doesn't know where the control is supposed to be added in the page. I could add the control to the page, run FindControl, then remove it from the page, but that seems even hackier than just doing a recursive search by hand.
Fishtoaster
I do not understand y u need to do a findControl. since you are creating the literal y cant u hold on to the variable till u add it to the page and from then on use Page.FindControl to get the control again.
Vinay B R
A: 

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;
    }
Fishtoaster