ASP.Net FindControl ne fonctionne pas - pourquoi?
j'ai utilisé FindControl
dans le passé, avant .NET 2.0/3.0. Il semble que maintenant, pour une raison quelconque, les pièces D'identité de mes contrôles obtiennent un funky nommé assigné. Par exemple, j'ai assigné un id "cbSelect" à une case à cocher, mais FindControl ne le trouve pas. Quand je regarde le HTML il a été assigné ctl00_bodyPlaceHolder_ctl02_cbSelect
.
Je n'ai trouvé aucun exemple de FindControl qui mentionne cela. En fait, tout le monde semble utiliser find control comme d'habitude.
alors, est-ce que je fais quelque chose de mal? N' .Net le changement? Quelqu'un peut jeter un peu de lumière sur ce, pour moi, c'est vraiment frustrant!
7 réponses
vous utilisez probablement une page maître ou des commandes utilisateur (ascx) et c'est la raison pour laquelle les ID du client changent. Imaginez que vous avez un contrôle dans la page principale avec le même id que celui dans la page. Il en résulterait des affrontements. Les changements d'id garantissent que toutes les propriétés ClientID sont uniques sur une page.
FindControl doit faire l'objet d'une attention particulière lors de L'utilisation de MasterPages. Jetez un oeil à ASP.NET 2.0 MasterPages et FindControl(). Le FindControl fonctionne à l'intérieur d'un nom du conteneur. La page D'accueil et la page sont des conteneurs de nommage différents.
Vous pouvez écrire extender pour trouver n'importe quel contrôle sur la page en utilisant récursion. Cela pourrait ê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);
}
j'ai eu assez de chance de travailler autour de ce problème dans "la plupart" des cas avec une méthode d'extension simple
Vous pouvez l'appeler sur n'importe quel contrôle de conteneur de niveau supérieur que vous pensez le mieux, y compris la Page elle-même si vous voulez scanner toute la hiérarchie de contrôle.
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;
}
lors de la recherche d'un contrôle dans une collection de contrôle, Utilisez toujours l'id que vous avez assigné au contrôle, pas celui que vous voyez dans le rendu du post source. Si FindControl () ne trouve pas le contrôle que vous savez exister, il y a de fortes chances que vous ne cherchiez pas dans la bonne branche de la hiérarchie de contrôle. 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
Dim form HtmlForm = CType(FindControlRecursive(Me, "Form"), HtmlForm)
C'est la VB.NET code 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 l'initiale VB.NET code. Je ne l'ai modifié qu'un tout petit peu, avec 2 changements fonctionnels: mine ne fait pas d'erreur si/quand null/Nothing est passé en tant que contrôle d'entrée, et mine est implémentée en tant qu'Extension. Mes 3 autres modifications mineures n'affectent pas la fonctionnalité, mais pour moi, elles étaient des simplifications de code. Mais je sais que c'est très subjectif.
cette méthode peut donc être utilisée avec:
Dim c1 As Control = Page.FindChildControlById("aspControlID")
et si vous voulez le convertir en une classe spécifique d'enfant D'un contrôle, comme ceci:
Dim c1 As Control = Page.FindChildControlById("aspControlID")
Dim c As HyperLink = TryCast(c1, HyperLink)
mise à jour: ma fonction S'appelle maintenant 'FindChildControlById' (auparavant 'FindMiControl'). Je préférais la suggestion de SpeedNet.
quand il rend le html, ASP.NET préfixe toutes les ID de contrôle avec les Id des conteneurs de nom (contrôle de L'utilisateur, etc..) dans une hiérarchie remontant jusqu'à la racine du document. Cela garantit que tous les ID sont uniques pour les dos de poteau, etc..
ceci n'affecte pas L'utilisation de FindControl où vous devez utiliser L'ID dans le markup original.
Voici une référence sur la façon dont les contrôles de formulaires web sont nommés...