2010-08-24 7 views
4

de code Exemple:Trouble with FindControl et contrôles dynamicly créés

var div = new HtmlGenericControl("div"); 
    div.Controls.Add(new Literal() { ID = "litSomeLit" }); 
    var lit = (Literal)div.FindControl("litSomeLit"); 
    Assert.IsNotNull(lit); 

Ce code échoue assert, car nul est allumé. Le débogage montre que div.Controls contient définitivement un littéral avec l'ID de "litSomeLit". Mes questions sont "Pourquoi?" et "Y at-il un moyen d'obtenir un contrôle d'un ID spécifique sans faire une recherche récursive de div.Controls [] à la main un élément à la fois?"

La raison pour laquelle je fais les choses de cette façon est que mon application actuelle n'est pas si simple - une méthode que j'écris est donné un contrôle complexe avec plusieurs sous-contrôles dans un certain nombre de configurations possibles. J'ai besoin d'accéder à un contrôle spécifique plusieurs couches vers le bas (par exemple, le contrôle avec l'ID "txtSpecificControl" pourrait être à StartingControl.Controls[0].Controls[2].Controls[1].Controls[3]). Normalement, je pourrais juste faire FindControl("txtSpecificControl"), mais cela ne semble pas fonctionner quand les contrôles ont été créés dynamiquement (comme dans l'exemple de code ci-dessus).

Répondre

4

Près de ce que je peux dire, il n'y a aucun moyen de faire ce que j'essaye d'accomplir sans ajouter le contrôle à la page. Si je devais deviner, je dirais que FindControl utilise la propriété UniqueID du contrôle, qui contient généralement les ID de tous les contrôles au-dessus du contrôle actuel (par exemple OuterControlID $ LowerControlId $ TargetControlID). Cela ne serait généré que lorsque le contrôle est ajouté à la page.

Quoi qu'il en soit, voici une implémentation de récursive profondeur première recherche FindControl qui va fonctionner lorsque le contrôle est pas attaché à la page encore:

public static Control FindControl(Control parent, string id) 
    { 
     foreach (Control control in parent.Controls) 
     { 
      if (control.ID == id) 
      { 
       return control; 
      } 
      var childResult = FindControl(control, id); 
      if (childResult != null) 
      { 
       return childResult; 
      } 
     } 
     return null; 
    } 
+0

+1 Belle fonction récursive. Très utile – brenjt

0

Lorsque vous avez confirmé que le contrôle se trouvait dans la collection Contrôles, l'avez-vous fait en inspectant directement la collection? FindControl() peut ne pas fonctionner dans ce contexte.

Lorsque vous déboguez le test, le var lit est-il nul? Si c'est le cas, vous devrez peut-être accéder à l'index membre par élément au lieu d'utiliser la méthode FindControl().

+0

A) Oui, en examinant la collection Controls du contrôle. Cependant, le test suivant passe très bien: http://snipt.net/fishtoaster/findcontrol/ ce qui impliquerait que FindControl devrait être capable de le trouver. B) Err, oui. C'est tout le point de la question - pourquoi est-ce nul, et/ou comment puis-je contourner ce fait sans avoir à passer par tout l'index des articles (ce qui serait fastidieux, puisque je ne sais pas exactement à quelle profondeur et à quel index mon contrôle cible est)? – Fishtoaster

2

Changer votre code

var div = new HtmlGenericControl("div"); 
Page.Controls.Add(div); 
div.Controls.Add(new Literal() { ID = "litSomeLit" }); 
var lit = (Literal)div.FindControl("litSomeLit"); 

En autant que je sache FindControl ne fonctionne que lorsque le contrôle est dans l'arbre visuel de la page.

+0

Je ne peux pas faire ce changement, car ma méthode ne sait pas où le contrôle est censé être ajouté dans la page. Je pourrais ajouter le contrôle à la page, lancer FindControl, puis le retirer de la page, mais cela semble encore plus compliqué que de faire une recherche récursive à la main. – Fishtoaster

+0

Je ne comprends pas que vous ayez besoin de faire un findControl. Puisque vous créez littéralement vous ne pouvez pas conserver la variable jusqu'à ce que vous l'ajoutiez à la page et à partir de ce moment utilisez Page.FindControl pour reprendre le contrôle. –