web-dev-qa-db-de.com

ASP.Net FindControl funktioniert nicht - wie kommt das?

Ich habe FindControl in der Vergangenheit vor .NET 2.0/3.0 verwendet. Es scheint, als würden jetzt aus irgendeinem Grund die IDs meiner Steuerelemente mit einem Funknamen versehen. Beispielsweise habe ich einer Checkbox eine ID "cbSelect" zugewiesen, FindControl findet sie jedoch nicht. Beim Anzeigen des HTML-Codes wurde ctl00_bodyPlaceHolder_ctl02_cbSelect zugewiesen.

Ich habe kein Beispiel für FindControl gefunden, das das erwähnt. Tatsächlich scheint jeder die Suchsteuerung wie gewohnt zu benutzen.

Mache ich etwas falsch? Hat sich .Net geändert? Kann jemand etwas Licht auf mich werfen, ist es wirklich frustrierend!

28
LilMoke

Sie verwenden wahrscheinlich ein MasterPage- oder ein Benutzersteuerelement (ascx), weshalb sich die Client-IDs ändern. Stellen Sie sich vor, Sie haben ein Steuerelement auf der Masterseite mit derselben ID wie eines auf der Seite. Dies würde zu Konflikten führen. Die ID-Änderungen stellen sicher, dass alle ClientID-Eigenschaften auf einer Seite eindeutig sind. 

FindControl erfordert bei der Arbeit mit MasterPages besondere Aufmerksamkeit. Schauen Sie sich ASP.NET 2.0 MasterPages und FindControl () an. Das FindControl arbeitet in einem Namenscontainer . Die MastePage und die Seite sind unterschiedliche Namenscontainer.

29
Aleris

Ich habe ziemlich viel Glück gehabt, dieses Problem in "den meisten" Fällen mit einer einfachen Erweiterungsmethode zu umgehen

Sie können es für das übergeordnete Containersteuerelement aufrufen, das Sie für am besten halten, einschließlich der Seite selbst, wenn Sie die gesamte Steuerelementhierarchie durchsuchen möchten. 

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;
}
8
Stephen M. Redd

Sie können einen Extender schreiben, um jedes Steuerelement auf der Seite mithilfe von Rekursion zu finden. Dies könnte in einer Util/Helper-Klasse sein.

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

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

    public static Control FindControlRecursive(string controlId, Control parent)
    {
        foreach (Control control in parent.Controls)
        {
            Control result = FindControlRecursive(controlId, control);
            if (result != null)
            {
                return result;
            }
        }
        return parent.FindControl(controlId);
    }
8
nemke

Verwenden Sie bei der Suche nach einem Steuerelement in einer Steuerelementsammlung immer die ID, die Sie dem Steuerelement zugewiesen haben, nicht die ID, die Sie im Quell-Nachrendern sehen. Wenn FindControl () das von Ihnen bekannte Steuerelement nicht findet, besteht eine gute Chance, dass Sie nicht im rechten Zweig der Steuerelementhierarchie suchen. Eine rekursive Funktion war für mich erfolgreich.

Hier ist mein Beispiel für das, was ich für VB.NET 3.5 verwende:

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

Hier ein Beispiel, wie ich diese Funktion in meiner Basisseitenklasse aktuell implementieren würde:

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

Dies ist der VB.NET-Code, der für mich funktioniert hat:

<Extension()> _
Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
    If controlToStartWith Is Nothing Then Return Nothing
    If controlToStartWith.ID = controlIdToFind Then Return controlToStartWith
    For Each childControl As Control In controlToStartWith.Controls
        Dim resCtrl As Control = FindChildControlById(childControl, controlIdToFind)
        If resCtrl IsNot Nothing Then Return resCtrl
    Next childControl
    Return Nothing
End Function ' Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control

Die Gutschrift geht an George für den ursprünglichen VB.NET-Code. Ich habe es nur ein kleines bisschen geändert, mit 2 funktionalen Änderungen: Meiner ist kein Fehler, wenn/als Null/Nothing als Eingabesteuerung übergeben wird, und Meines ist als Erweiterung implementiert. Meine anderen drei geringfügigen Änderungen wirken sich nicht auf die Funktionalität aus, aber für mich waren das Code-Vereinfachungen. Aber ich weiß, dass es sehr subjektiv ist.

Diese Methode kann also verwendet werden mit:

Dim c1 As Control = Page.FindChildControlById("aspControlID")

Und wenn Sie es in eine bestimmte untergeordnete Klasse eines Controls konvertieren möchten, wie folgt:

Dim c1 As Control = Page.FindChildControlById("aspControlID")
Dim c As HyperLink = TryCast(c1, HyperLink)

Update: Meine Funktion heißt jetzt 'FindChildControlById' (vorher war 'FindMiControl'). Der Vorschlag von SpeedNet hat mir besser gefallen.

3
Shawn Kovac

Beim Rendern der HTML-Datei werden von ASP.NET alle Steuerelement-IDs mit den IDs der Benennungscontainer (Benutzersteuerelemente usw.) in einer Hierarchie vorangestellt, die bis zum Stamm des Dokuments reicht. Dadurch wird sichergestellt, dass alle IDs für Postbacks usw. eindeutig sind.

Dies gilt nicht für die Verwendung von FindControl, wo Sie die ID im ursprünglichen Markup verwenden sollten.

1
Nick

Hier finden Sie eine Referenz, wie Webformular-Steuerelemente benannt werden ...

Web Forms Control Identifikation

0
George