我一直在考虑如何获取页面上的所有控件并对它们执行任务,下面是相关问题的链接:
我需要一段代码来扫描页面,获取所有DropDownList控件,并将它们返回到列表中。
我目前必须编辑每个单独的控件,我更愿意能够动态地遍历每个控件以执行我的任务。
我一直在考虑如何获取页面上的所有控件并对它们执行任务,下面是相关问题的链接:
我需要一段代码来扫描页面,获取所有DropDownList控件,并将它们返回到列表中。
我目前必须编辑每个单独的控件,我更愿意能够动态地遍历每个控件以执行我的任务。
请查看我的之前在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);
}
}
List<DropDownList> allControls = new List<DropDownList>();
GetControlList<DropDownList>(Page.Controls, allControls )
foreach (var childControl in allControls )
{
// call for all controls of the page
}
[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;
}
}
}
}
}
由于 this
关键字的存在,这些方法成为了扩展方法,可以简化代码。
例如,要查找页面中的所有 DropDownList
,只需调用以下方法:
var allDropDowns = this.Page.FindControl<DropDownList>();
由于使用了yield
关键字,以及Linq足够聪明地推迟了枚举的执行,你可以调用以下代码(例如):
var allDropDowns = this.Page.FindDescendants<DropDownList>();
var firstDropDownWithCustomClass = allDropDowns.First(
ddl=>ddl.CssClass == "customclass"
);
First
方法中的断言时停止。整个控件树不会被遍历。foreach (DropDownList dr in this.Page.Form.Controls.OfType<DropDownList>())
{
}
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;
}
插入到你的类中(静态可选)。
我曾经有过这个问题,虽然我发现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;
}
}
}
}
在页面上循环控件并不难 - 你只需要在每个控件内查找更多的控件。
你可以像这样做:
foreach(var control in Page)
{
if(control is DropDownList)
{
//Do whatever
}
else
{
//Call this function again to search for controls within this control
}
}
您可以使用递归逻辑来获取所有控件,如下所示:
private void PopulateSelectList(Control parentCtrl, List<DropDownList> selectList)
{
foreach (Control ctrl in parentCtrl.Controls)
{
if (ctrl is DropDownList)
{
selectList.Add(((DropDownList)ctrl);
continue;
}
FindAllControls(ctrl, selectList);
}
}
如果您使用system.web.ui中的表单组件,则此方法有效。但是,如果您从system.web.mvc中使用它们,则此方法无效。因此,我想出了以下解决方法。
for (Int32 idx = 0; idx < formCollection.Count; idx += 1)
{
String Name = formCollection.Keys[idx];
String value = formCollection[idx];
if (Name.Substring(0, 3).ToLower() == "chk")
{
Response.Write(Name + " is a checkbox <br/>");
}
else if (Name.Substring(0, 5).ToLower() == "txtar")
{
Response.Write(Name + " is a text area <br/>");
}
else if (Name.Substring(0, 2).ToLower() == "rd")
{
Response.Write(Name + " is a RadioButton <br/>");
}
}
这对我来说是有效的,但我发现如果单选按钮未被选择,则为null,因此不会返回任何内容,这是可以的,如果为null,则无需将任何内容写入数据库
var dropDownLists = new List<DropDownList>();
foreach (var control in this.Controls)
{
if (control is DropDownList)
{
dropDownLists.Add( (DropDownList)control );
}
}