获取页面上特定类型的所有Web控件

Ani*_*cho 31 c# asp.net webforms

我一直在思考如何在页面上获取所有控件,然后在相关问题中对它们执行任务:

如何通过编程方式搜索C#DropDownList

我需要可以扫描页面的代码,获取所有DropDownList控件并将它们返回到列表中.

我目前不得不编辑每个单独的控件,我宁愿能够动态循环每个控件来执行我的任务.

Ste*_*e B 59

检查我以前的SO答案.

基本上,我们的想法是使用以下方法包装迭代控件集合的递归:

private void GetControlList<T>(ControlCollection controlCollection, List<T> resultCollection)
where T : Control
{
    foreach (Control control in controlCollection)
    {
        //if (control.GetType() == typeof(T))
        if (control is T) // This is cleaner
            resultCollection.Add((T)control);

        if (control.HasControls())
            GetControlList(control.Controls, resultCollection);
    }
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

List<DropDownList> allControls = new List<DropDownList>();
GetControlList<DropDownList>(Page.Controls, allControls )
foreach (var childControl in allControls )
{
//     call for all controls of the page
}
Run Code Online (Sandbox Code Playgroud)

[2013年11月26日编辑]:这是实现这一目标的更优雅方式.我编写了两个扩展方法,可以在两个方向上遍历控制树.这些方法以更Linq的方式编写,因为它产生了一个可枚举的:

/// <summary>
/// Provide utilities methods related to <see cref="Control"/> objects
/// </summary>
public static class ControlUtilities
{
    /// <summary>
    /// Find the first ancestor of the selected control in the control tree
    /// </summary>
    /// <typeparam name="TControl">Type of the ancestor to look for</typeparam>
    /// <param name="control">The control to look for its ancestors</param>
    /// <returns>The first ancestor of the specified type, or null if no ancestor is found.</returns>
    public static TControl FindAncestor<TControl>(this Control control) where TControl : Control
    {
        if (control == null) throw new ArgumentNullException("control");

        Control parent = control;
        do
        {
            parent = parent.Parent;
            var candidate = parent as TControl;
            if (candidate != null)
            {
                return candidate;
            }
        } while (parent != null);
        return null;
    }

    /// <summary>
    /// Finds all descendants of a certain type of the specified control.
    /// </summary>
    /// <typeparam name="TControl">The type of descendant controls to look for.</typeparam>
    /// <param name="parent">The parent control where to look into.</param>
    /// <returns>All corresponding descendants</returns>
    public static IEnumerable<TControl> FindDescendants<TControl>(this Control parent) where TControl : Control
    {
        if (parent == null) throw new ArgumentNullException("control");

        if (parent.HasControls())
        {
            foreach (Control childControl in parent.Controls)
            {
                var candidate = childControl as TControl;
                if (candidate != null) yield return candidate;

                foreach (var nextLevel in FindDescendants<TControl>(childControl))
                {
                    yield return nextLevel;
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

由于this关键字,这些方法是扩展方法,可以简化代码.

例如,要查找DropDownList页面中的所有内容,您只需调用:

var allDropDowns = this.Page.FindControl<DropDownList>();
Run Code Online (Sandbox Code Playgroud)

由于使用了yield关键字,并且因为Linq足够智能来推迟执行枚举,所以可以调用(例如):

var allDropDowns = this.Page.FindDescendants<DropDownList>();
var firstDropDownWithCustomClass = allDropDowns.First(
    ddl=>ddl.CssClass == "customclass"
    );
Run Code Online (Sandbox Code Playgroud)

只要First满足方法中的谓词,枚举就会停止.整个控制树不会走路.


mar*_*rko 15

foreach (DropDownList dr in this.Page.Form.Controls.OfType<DropDownList>())
{

}
Run Code Online (Sandbox Code Playgroud)

  • 为了使其正常工作,它应该是递归的. (2认同)

小智 5

有这个问题,虽然我发现Steve B的答案很有用,但我想要一个扩展方法,所以重新考虑它:

    public static IEnumerable<T> GetControlList<T>(this ControlCollection controlCollection) where T : Control
    {
        foreach (Control control in controlCollection)
        {
            if (control is T)
            {
                yield return (T)control;
            }

            if (control.HasControls())
            {
                foreach (T childControl in control.Controls.GetControlList<T>())
                {
                    yield return childControl;
                }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)


Gre*_*rle 5

这是一个递归版本,它返回所请求类型的控件集合,而不是使用另一个参数:

using System.Collections.Generic;
using System.Web.UI;
// ...
public static List<T> GetControls<T>(ControlCollection Controls)
where T : Control {
  List<T> results = new List<T>();
  foreach (Control c in Controls) {
    if (c is T) results.Add((T)c);
    if (c.HasControls()) results.AddRange(GetControls<T>(c.Controls));
  }
  return results;
}
Run Code Online (Sandbox Code Playgroud)

插入您的班级(静态可选).