在ASP.NET中找到控件的更好方法

时间:2011-02-10 10:13:58

标签: asp.net findcontrol

我有一个复杂的asp.net表单,在一个表单中有50到60个字段,就像Multiview一样,在MultiView中我有一个GridView,而在GridView中我有几个{{1 }}

目前我正在使用CheckBoxes方法的链接并检索子ID。

现在,我的问题是,在ASP.NET中找到嵌套控件还有其他方法/解决方案。

9 个答案:

答案 0 :(得分:72)

如果您正在寻找特定类型的控件,您可以使用像这样的递归循环 - http://weblogs.asp.net/eporter/archive/2007/02/24/asp-net-findcontrol-recursive-with-generics.aspx

这是我做的一个例子,它返回给定类型的所有控件

/// <summary>
/// Finds all controls of type T stores them in FoundControls
/// </summary>
/// <typeparam name="T"></typeparam>
private class ControlFinder<T> where T : Control 
{
    private readonly List<T> _foundControls = new List<T>();
    public IEnumerable<T> FoundControls
    {
        get { return _foundControls; }
    }    

    public void FindChildControlsRecursive(Control control)
    {
        foreach (Control childControl in control.Controls)
        {
            if (childControl.GetType() == typeof(T))
            {
                _foundControls.Add((T)childControl);
            }
            else
            {
                FindChildControlsRecursive(childControl);
            }
        }
    }
}

答案 1 :(得分:17)

像往常一样晚。如果有人仍对此感兴趣,则会有一些相关的SO questionsanswers。我的版本的递归扩展方法解决了这个问题:

public static IEnumerable<T> FindControlsOfType<T>(this Control parent)
                                                        where T : Control
{
    foreach (Control child in parent.Controls)
    {
        if (child is T)
        {
            yield return (T)child;
        }
        else if (child.Controls.Count > 0)
        {
            foreach (T grandChild in child.FindControlsOfType<T>())
            {
                yield return grandChild;
            }
        }
    }
}

答案 2 :(得分:8)

所有突出显示的解决方案都使用递归(性能代价高昂)。这是没有递归的更清洁的方式:

public T GetControlByType<T>(Control root, Func<T, bool> predicate = null) where T : Control 
{
    if (root == null) {
        throw new ArgumentNullException("root");
    }

    var stack = new Stack<Control>(new Control[] { root });

    while (stack.Count > 0) {
        var control = stack.Pop();
        T match = control as T;

        if (match != null && (predicate == null || predicate(match))) {
            return match;
        }

        foreach (Control childControl in control.Controls) {
           stack.Push(childControl);
        }
    }

    return default(T);
}

答案 3 :(得分:6)

FindControl不会递归搜索嵌套控件。它只能找到NamigContainer是您正在调用FindControl的控件的控件。

这是一个原因,默认情况下,ASP.Net不会递归地查看您的嵌套控件:

  • 性能
  • 避免错误
  • 复用性

考虑到您希望将GridView,Formviews,UserControl等封装在其他UserControl中,以实现可重用性。如果您已经在页面中实现了所有逻辑并使用递归循环访问这些控件,那么很难重构它。如果您已经通过事件处理程序(例如GridView的RowDataBound)实现了逻辑和访问方法,那么它将更简单,更不容易出错。

答案 4 :(得分:1)

控件上的操作管理

在基类中创建下面的类。 类要获得所有控件:

public static class ControlExtensions
{
    public static IEnumerable<T> GetAllControlsOfType<T>(this Control parent) where T : Control
    {
        var result = new List<T>();
        foreach (Control control in parent.Controls)
        {
            if (control is T)
            {
                result.Add((T)control);
            }
            if (control.HasControls())
            {
                result.AddRange(control.GetAllControlsOfType<T>());
            }
        }
        return result;
    }
}

来自数据库: 在DATASET(DTActions)中获取所有动作ID(如divAction1,divAction2 ....)允许特定用户。

在Aspx中: 在HTML中将动作(按钮,锚点等)放在div或span中,并为它们赋予像

这样的ID
<div id="divAction1" visible="false" runat="server" clientidmode="Static">   
                <a id="anchorAction" runat="server">Submit
                        </a>                      
                 </div>

IN CS: 在您的页面上使用此功能:

private void ShowHideActions()
    {

        var controls = Page.GetAllControlsOfType<HtmlGenericControl>();

        foreach (DataRow dr in DTActions.Rows)
        {          

            foreach (Control cont in controls)
            {

                if (cont.ClientID == "divAction" + dr["ActionID"].ToString())
                {
                    cont.Visible = true;
                }

            }
        }
    }

答案 5 :(得分:1)

递归查找与指定谓词匹配的所有控件(不包括根控件):

    public static IEnumerable<Control> FindControlsRecursive(this Control control, Func<Control, bool> predicate)
    {
        var results = new List<Control>();

        foreach (Control child in control.Controls)
        {
            if (predicate(child))
            {
                results.Add(child);
            }
            results.AddRange(child.FindControlsRecursive(predicate));
        }

        return results;
    }

用法:

myControl.FindControlsRecursive(c => c.ID == "findThisID");

答案 6 :(得分:1)

我决定只构建控件字典。难以维护,可能比递归FindControl()运行得更快。

protected void Page_Load(object sender, EventArgs e)
{
  this.BuildControlDics();
}

private void BuildControlDics()
{
  _Divs = new Dictionary<MyEnum, HtmlContainerControl>();
  _Divs.Add(MyEnum.One, this.divOne);
  _Divs.Add(MyEnum.Two, this.divTwo);
  _Divs.Add(MyEnum.Three, this.divThree);

}

在我因为没有回答OP的问题而大笑之前......

问:现在,我的问题是,是否有其他方法/解决方案可以在ASP.NET中找到嵌套控件? 答:是的,首先要避免搜索它们。为什么搜索你已经知道的东西?最好构建一个允许引用 已知对象的系统。

答案 7 :(得分:1)

https://blog.codinghorror.com/recursive-pagefindcontrol/

Page.FindControl("DataList1:_ctl0:TextBox3");

OR

private Control FindControlRecursive(Control root, string id)
{
    if (root.ID == id)
    {
        return root;
    }
    foreach (Control c in root.Controls)
    {
        Control t = FindControlRecursive(c, id);
        if (t != null)
        {
            return t;
        }
    }
    return null;
}

答案 8 :(得分:0)

以下示例定义了Button1_Click事件处理程序。调用时,此处理程序使用FindControl方法在包含页面上查找ID属性为TextBox2的控件。如果找到控件,则使用Parent属性确定其父级,并将父控件的ID写入页面。如果找不到TextBox2,则会向页面写入“Control Not Found”。

private void Button1_Click(object sender, EventArgs MyEventArgs)
{
      // Find control on page.
      Control myControl1 = FindControl("TextBox2");
      if(myControl1!=null)
      {
         // Get control's parent.
         Control myControl2 = myControl1.Parent;
         Response.Write("Parent of the text box is : " + myControl2.ID);
      }
      else
      {
         Response.Write("Control not found");
      }
}