C#查找控件及控件引用

4
如何在c#中引用控件(运行时)而不使用ID?
例如,我有一个包含一个表格的页面。我将使用XMLHttp递归加载此页面,因此无法使用其ID引用该表格。是否有类似于this.Page.Controls[2]Controls["Tables"][0]的东西?
我尝试使用名称this.Controls.Find("MyTableName", true);,但需要引用库System.Windows.Forms(我认为),但不知道如何添加它,因为'using System.'智能感知无法看到它。
我循环遍历了this.Controls中的所有控件,但是'system.ui.web.control'不包含'.Name'的定义,因此我只能搜索ID。
我是新手,我相信解决方案非常简单。
提前感谢。

我想我真的不太理解 - 在页面生命周期的哪个阶段,您会在客户端加载DOM的同时向服务器发出请求? - Matthew Groves
数据集显示在一个非常大的树中,一次性加载整个树是不可行的,因此我会在用户展开节点时动态加载每个节点。 - Praesagus
1个回答

12

要在页面上找到控件,它必须是一个服务器控件,像这样:

<asp:Table runat="server">
   ...
</asp:Table>

页面上的常规HTML不是“控件”,它们只是发送到浏览器的文本。另一方面,服务器控件是实际的.NET类,可以与代码后台交互。

您仍然可以通过搜索其容器的Controls集合或递归搜索页面来获取此控件的句柄。让我们从递归搜索Controls集合开始:

Controls集合仅指给定控件的直接子控件。或者是页面的直接子控件。这些控件反过来有自己的子控件。它代表了内存中的树形结构。

以下是一种方法,从给定的控件向下递归遍历树,并按ID查找控件:

private Control FindControlRecursive(Control control, string id)
{
    Control returnControl = control.FindControl(id);
    if (returnControl == null)
    {
        foreach (Control child in control.Controls)
        {
            returnControl = child.FindControlRecursive(id);
            if (returnControl != null && returnControl.ID == id)
            {
                return returnControl;
            }
        }
    }
    return returnControl;
}

此答案的范围之外,更好的方法是使用扩展方法

如果要通过除其ID之外的内容查找控件,可以按类型搜索:

if(someControl is System.Web.UI.WebControls.Table)

请注意,这通常不是一个很好的主意。如果你最终需要以这种方式搜索控件,那么这不是一个很好的模式 - 你应该在控件上有一个ID或者你应该已经有对它的引用,因为它是通过代码创建的。
然而,修改该方法以递归搜索类型很容易:
private Control FindTable(Control startFrom)
{
    foreach(Control child in startFrom.Controls)
    {
        if(child is System.Web.UI.WebControls.Table)
        {
            return child;
        }
        else
        {
            return FindTable(child);
        }
    }
    return null;
}

您可以使用一种通用形式的此方法:
```html

您也可以使用此方法的通用表单:

```
private Control FindControl<T>(Control startFrom)
{
    foreach(Control child in startFrom.Controls)
    {
        if(child.GetType().IsAssignableFrom(typeof(T)))
        {
            return child;
        }
        else
        {
            return FindControl<T>(child);
        }
    }
    return null;
}

您绝对不需要包括System.Windows.Forms,因为那只是包含了WinForms应用程序的所有代码。这就是为什么Visual Studio没有在Web项目中为您包含它-您永远不需要它。System.Web.UI包含了所有Web控件所需的东西。


我不知道为什么会被踩 - 是那个删除了自己回答的人心态不好吗?所以,如果我使用你的想法按类型搜索,我应该将哪种参数类型定义为我的通用类型,以便我可以向我的方法发送其他类型的控件。if(myControl is arg)? - Praesagus
@Praesagus 我添加了代码以演示按类型而非ID进行搜索。但我不建议使用这种方法... - Rex M
非常感谢您抽出时间回答所有问题。我采纳了您的建议,重构了代码,使表在运行时创建,并且现在有一个对它的引用。然而,如果将来需要找到没有ID的控件,我仍然面临同样的问题。 - Praesagus
@Praesagus 我在回答中的观点是,你首先不应该真正需要这样做。如果你遇到需要这样做的情况,那就意味着你正在走错的道路上。像我提供的代码一样的代码表明它在技术上是可能的,但仍然是一个hack。当你需要快速解决一个丑陋的情况时,hack是可以接受的,但最好还是避免使用。 - Rex M
FindControlRecursive 方法中,你像调用扩展方法一样递归调用它: child.FindControlRecursive(id),但其实它并不是扩展方法,因此出现了错误。所以要么将该方法改为扩展方法,要么从内部改变调用方式:FindControlRecursive(child, id) - Sergej Popov
如果我想从我的 asp.net 文件中引用正在使用的包含文件中的 ID,该怎么办? - SearchForKnowledge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接