web-dev-qa-db-fra.com

ASP.Net FindControl ne fonctionne pas - Comment se fait-il?

J'ai utilisé FindControl dans le passé, avant .NET 2.0/3.0. Il semble que maintenant, pour une raison quelconque, les identifiants de mes contrôles reçoivent un nom génial attribué. Par exemple, j'ai affecté un identifiant "cbSelect" à une case à cocher, mais FindControl ne le trouve pas. Lorsque je visualise le code HTML, il a été attribué à ctl00_bodyPlaceHolder_ctl02_cbSelect.

Je n'ai pas trouvé d'exemple de FindControl qui mentionne cela. En fait, tout le monde semble simplement utiliser le contrôle de la recherche comme d'habitude.

Alors, est-ce que je fais quelque chose de mal? Est-ce que .Net a changé? Quelqu'un peut-il m'éclairer à ce sujet, c'est vraiment frustrant!

28
LilMoke

Vous utilisez probablement un MasterPage ou des contrôles utilisateur (ascx) et c’est la raison pour laquelle les identifiants client changent. Imaginez que vous ayez un contrôle dans la page maître avec le même identifiant que celui de la page. Cela entraînerait des affrontements. Les modifications apportées à l'ID garantissent que toutes les propriétés ClientID sont uniques sur une page. 

FindControl nécessite une attention particulière lors de l'utilisation de MasterPages. Consultez ASP.NET 2.0 MasterPages et FindControl () . FindControl fonctionne dans un conteneur naming . Le MastePage et la page sont des conteneurs de nommage différents.

29
Aleris

J'ai eu assez de chance en travaillant sur ce problème dans "la plupart" des cas avec une méthode d'extension simple

Vous pouvez l'appeler sur le contrôle de conteneur de niveau supérieur de votre choix, y compris la page si vous souhaitez analyser l'ensemble de la hiérarchie des contrôles. 

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

Vous pouvez écrire une extension pour trouver n'importe quel contrôle sur la page en utilisant la récursivité . Cela peut être dans une classe Util/Helper.

 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

Lors de la recherche d'un contrôle dans une collection de contrôles, utilisez toujours l'ID que vous avez attribué au contrôle, et non celui que vous voyez dans le post-rendu source. Si FindControl () ne trouve pas le contrôle que vous savez existe, il y a de bonnes chances que vous ne cherchiez pas dans la bonne branche de la hiérarchie des contrôles. Une fonction récursive a été un succès pour moi.

Voici mon exemple de ce que j'utilise pour 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

Voici un exemple de la façon dont j'implémenterais topiquement cette fonction dans ma classe de page de base:

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

C'est le code VB.NET qui a fonctionné pour moi:

<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

Le crédit va à George pour le code initial VB.NET. Je l'ai seulement modifié un tout petit peu, avec 2 changements fonctionnels: le mien ne fait pas d'erreur si/quand null/rien n'est passé en tant que contrôle d'entrée, et le mien est implémenté en tant qu'extension. Mes 3 autres modifications mineures n'affectent pas la fonctionnalité, mais pour moi, il s'agissait de simplifications de code. Mais je sais que c'est très subjectif.

Donc, cette méthode peut être utilisée avec:

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

Et si vous souhaitez le convertir en une classe enfant spécifique d’un contrôle, procédez comme suit:

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

Mise à jour: Ma fonction s'appelle désormais 'FindChildControlById' (auparavant appelée 'FindMiControl'). J'ai mieux aimé la suggestion de SpeedNet.

3
Shawn Kovac

Lors du rendu du code HTML, ASP.NET préfixera tous les ID de contrôle avec les ID des conteneurs de nommage (Contrôles utilisateur, etc.) dans une hiérarchie allant jusqu'à la racine du document. Cela garantit que tous les identifiants sont uniques pour les post-backs, etc.

Cela n'affecte pas l'utilisation de FindControl où vous devez utiliser l'ID dans le balisage d'origine.

1
Nick

Voici une référence à la façon dont les contrôles de formulaire Web sont nommés ...

Identification du contrôle des formulaires Web

0
George