asp.netfindcontrol

FindControl and INamingContainer


I want to word this question carefully, so helpful people don't jump in and spend their time telling me information that I already know (I don't want to waste their time).

I want to understand how FindControl works in ASP.NET web application projects (the ones where the c# files are referenced as CodeBehind, NOT CodeFile, in the markup).

Code behind have two files which sit between the markup file. E.g. Default.aspx will have Default.aspx.cs and Default.aspx.designer.cs

If you put a button on a page, it is added to the designer file. For example: protected global::System.Web.UI.WebControls.LinkButton LinkButton1;

If you want to get a reference to that control, it is immediately available as a member of the Default class. E.g. this.LinkButton1.Text = "Click Me";

If you look at a trace for the page, it is given a unique id as per the behaviour for INamingContainers (here, the Page): ctl00$ContentPlaceHolder1$LinkButton1

The thing I don't understand is why a null is returned by the statement: Control c = Page.FindControl("LinkButton1");

I realise this is unnecessary, as the button is already available to the Default class. And this is because it appears as a member in the Default.aspx.designer.cs file.

The thing I do not understand is why null is returned. Because the Page implements INamingContainer, and the button has an ID which correlates to that expected of a control in an INamingContainer. Isn't this exactly the kind of thing FindControl finds?


Solution

  • This behaviour was new to me, maybe because i wouldn't try to search for a control that is directly accessible anyway. I think this might also be the reason why ASP.NET not even allow this, because it's faster and safer to use an existing reference than to find it (or not).

    The FindControl method can be used to access a control whose ID is not available at design time. The method searches only the page's immediate, or top-level, container; it does not recursively search for controls in naming containers contained on the page. To access controls in a subordinate naming container, call the FindControl method of that container.

    http://msdn.microsoft.com/en-us/library/31hxzsdw.aspx

    Edit: After i checked this behaviour, i've noticed that null is only returned if used on a Page with MasterPage, since the only control in the page's ControlCollection is the MasterPage itself. That makes sense. You cannot guarantee an ID to be unique when the control is on the top level of a page with MasterPage, because other ContentPages might as well have a control with this ID and FindControl could today return another control than tomorrow.

    If you look at the NamingContainer of the Control you want to find, you see that in case of a MasterPage it is the ContentPlaceHolder and in case of a "normal" Page it is the Page itself.

    So you need to get a reference to the MasterPage's ContentPlaceholder first before you could find the control via FindControl:

    Page.Master.FindControl("ContentPlaceHolder1").FindControl("LinkButton1");
    

    http://msdn.microsoft.com/en-us/library/xxwa0ff0.aspx