views:

4235

answers:

6

I have used FindControl in the past, prior to .NET 2.0/3.0. It seems like now, for some reason, the ID's of my controls get a funky named assigned. For example I assigned an id "cbSelect" to a checkbox, but FindControl does not find it. When I view the HTML it was assigned ctl00_bodyPlaceHolder_ctl02_cbSelect.

I have not found one example of FindControl that mentions that. In fact everyone seems to just use find control like normal.

So, am I doing something wrong? Did .Net change? Can anyone shed some light onto this for me, it is really frustrating!

+8  A: 

You are probably using a MasterPage or user controls (ascx) and this is the reason the for client ids change. Imagine you have a control in the master page with the same id as one in the page. This would result in clashes. The id changes ensures all ClientID properties are unique on a page.

FindControl needs some special attention when working with MasterPages. Have a look at ASP.NET 2.0 MasterPages and FindControl(). The FindControl works inside a naming container. The MastePage and the page are different naming containers.

Aleris
+1  A: 

When it's rendering the html, ASP.NET will prefix all the control IDs with the IDs of the naming containers (User Controls etc..) in a hierarchy going back all the way to the document root. This ensures that all the IDs are unique for post backs etc..

This does not effect using FindControl where you should use the ID in the original markup.

Nick
A: 

Here is a reference as to how web form controls are named...

Web Forms Control Identification

George
+2  A: 

I've had pretty good luck working around this problem in "most" cases with a simple extension method

You can call it on whatever higher-level container control you think best, including the Page itself if you want to scan the entire control hierarchy.

private static Control FindControlIterative(this Control control, string id)
{
    Control ctl = control;

    LinkedList<Control> controls = new LinkedList<Control>();

    while(ctl != null)
    {
    if(ctl.ID == id)
    {
        return ctl;
    }
    foreach(Control child in ctl.Controls)
    {
        if(child.ID == id)
        {
     return child;
        }
        if(child.HasControls())
        {
     controls.AddLast(child);
        }
    }
    ctl = controls.First.Value;
    controls.Remove(ctl);
    }
    return null;
}
Stephen M. Redd
A: 

You could write extender to find any control on page using recursion. This could be in some Util/Helper class.

 public static Control FindAnyControl(this Page page, string controlId)
    {
        return FindControlReqursive(controlId, page.Form);
    }

    public static Control FindAnyControl(this UserControl control, string controlId)
    {
        return FindControlReqursive(controlId, control);
    }

    public static Control FindControlReqursive(string controlId, Control parent)
    {
        foreach (Control control in parent.Controls)
        {
            Control result = FindControlReqursive(controlId, control);
            if (result != null)
            {
                return result;
            }
        }
        return parent.FindControl(controlId);
    }
nemke
+1  A: 

When searching for a control in a control collection, always use the id you assigned the control, not the one you see in the source post render. If FindControl() does not find the control you know exists, there is a good chance that you are not searching in the right branch of the control hierarchy. A recursive function has been successful for me.

Here is my example of what I use for VB.NET 3.5:

Function FindControlRecursive(ByVal ctrl As Control, ByVal id As String) As Control
    Dim c As Control = Nothing

    If ctrl.ID = id Then
        c = ctrl
    Else
        For Each childCtrl In ctrl.Controls
            Dim resCtrl As Control = FindControlRecursive(childCtrl, id)
            If resCtrl IsNot Nothing Then c = resCtrl
        Next
    End If

    Return c
End Function

Here is an example of how I would topically implement this function in my base page class:

Dim form HtmlForm = CType(FindControlRecursive(Me, "Form"), HtmlForm)
George