ASP.Net FindControl不工作 – 怎么样?

我以前在.NET 2.0 / 3.0之前使用过FindControl 。 现在看来,由于某种原因,我的控件的ID得到了一个时髦的命名。 例如,我为复选框分配了一个id“cbSelect”,但FindControl找不到它。 当我查看HTML时,它被分配了ctl00_bodyPlaceHolder_ctl02_cbSelect

我还没有找到一个提到它的FindControl示例。 事实上,每个人似乎都像正常一样使用find控件。

那么,我做错了什么? .Net改变了吗? 任何人都可以为我解释这一点,这真的令人沮丧!

您可能正在使用MasterPage或用户控件(ascx),这就是客户端ID更改的原因。 想象一下,您在母版页中拥有一个控件,该控件的ID与页面中的控件相同。 这会导致冲突。 id更改确保所有ClientID属性在页面上都是唯一的。

使用MasterPages时,FindControl需要特别注意。 看看ASP.NET 2.0 MasterPages和FindControl() 。 FindControl在命名容器内部工作。 MastePage和页面是不同的命名容器。

您可以编写扩展程序以使用递归在页面上查找任何控件。 这可能在某些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); } 

通过简单的扩展方法,我在“大多数”情况下解决这个问题的运气相当不错

您可以在您认为最好的任何更高级别的容器控件上调用它,包括页面本身(如果您要扫描整个控件层次结构)。

 private static Control FindControlIterative(this Control control, string id) { Control ctl = control; LinkedList controls = new LinkedList(); 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; } 

在控件集合中搜索控件时,请始终使用您为控件分配的ID,而不是您在源文章渲染中看到的ID。 如果FindControl()找不到您知道的控件,则很可能您没有在控件层次结构的正确分支中进行搜索。 递归函数对我来说是成功的。

这是我用于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) 

这是适用于我的VB.NET代码:

  _ 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 

感谢乔治最初的VB.NET代码。 我只修改了一点,有2个function改变:如果/当null / Nothing作为输入控件传递时,我没有错误,并且我的实现为扩展。 我的其他3个小改动不会影响function,但对我来说,它们是代码简化。 但我知道这是非常主观的。

所以这个方法可以用于:

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

如果你想将它转换为Control的特定子类,如下所示:

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

更新:我的函数现在名为’FindChildControlById’(以前是’FindMiControl’)。 我更喜欢SpeedNet的建议。

当它呈现html时,ASP.NET将在所有控件ID前面加上命名容器(用户控件等)的ID,这些ID在层次结构中一直返回到文档根目录。 这确保了所有ID对于回发等都是唯一的。

这不会影响使用FindControl,您应该在原始标记中使用ID。

以下是关于如何命名Web表单控件的参考…

Web表单控件标识