29

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

我还没有找到一个提到这一点的 FindControl 示例。事实上,每个人似乎都只是像平常一样使用查找控件。

那么,我做错了吗?.Net 改变了吗?谁能帮我解释一下,这真的很令人沮丧!

4

7 回答 7

29

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

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

于 2009-04-28T20:30:20.087 回答
10

您可以编写扩展程序以使用递归查找页面上的任何控件。这可能在某些 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);
    }
于 2010-01-27T13:51:48.123 回答
8

在“大多数”情况下,我用简单的扩展方法解决了这个问题,我很幸运

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

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;
}
于 2009-04-28T20:56:22.707 回答
7

在控件集合中搜索控件时,始终使用您分配给控件的 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)
于 2010-03-02T20:57:02.197 回答
3

这是对我有用的 VB.NET 代码:

<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

最初的 VB.NET 代码要归功于 George。我只修改了一点点,有 2 个功能更改:如果/当 null/Nothing 作为输入控件传递时,我的不会出错,而我的作为扩展实现。我的其他 3 个小更改不会影响功能,但对我来说,它们是代码简化。但我知道这是非常主观的。

所以这个方法可以用于:

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 的建议。

于 2016-03-01T19:30:36.923 回答
1

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

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

于 2009-04-28T20:31:37.713 回答
0

这是有关如何命名 Web 表单控件的参考...

Web 表单控件标识

于 2009-04-28T20:32:37.930 回答