FindControl和动态创建控件的麻烦

示例代码:

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

此代码未通过断言,因为lit为null。 调试显示div.Controls肯定包含ID为“litSomeLit”的文字。 我的问题是“为什么?” 并且“有没有办法获得对特定ID的控制,而不是一次手动一个元素递归搜索div.Controls []?”

我这样做的原因是我的实际应用并不那么直接 – 我正在编写的一种方法在一些可能的配置中给出了一个带有几个子控件的复杂控制。 我需要访问几个层的特定控件(例如,ID为“txtSpecificControl”的控件可能位于StartingControl.Controls[0].Controls[2].Controls[1].Controls[3] )。 通常我可以做FindControl("txtSpecificControl") ,但是当控件刚刚动态创建时(例如上面的示例代码中),这似乎不起作用。

我可以说,在没有将控件添加到页面的情况下,没有办法完成我想要完成的任务。 如果我不得不猜测,我会说FindControl使用控件的UniqueID属性,该属性通常包含当前控件上方所有控件的ID(例如OuterControlID $ LowerControlId $ TargetControlID)。 只有当控件实际添加到页面时才会生成。

无论如何,这是一个递归深度优先搜索FindControl的实现,当控件没有附加到页面时它将起作用:

  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; } 

将您的代码更改为

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

据我所知,FindControl仅在控件位于页面的可视树中时才有效。

当您确认控件位于Controls集合中时,是否通过直接检查集合来执行此操作? FindControl()可能无法在此上下文中工作。

调试测试时,var是否为null? 如果是这样,您可能必须按项目索引访问,而不是使用FindControl()方法。