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

我有一个复杂的asp.net窗体,甚至有50到60个字段在一个forms就像有多Multiview ,在MultiView里面我有一个GridView ,在GridView里面我有几个CheckBoxes

目前我正在使用FindControl()方法的链接和检索子ID。

现在,我的问题是,是否有任何其他方式/解决scheme来findASP.NET中的嵌套控件。

如果你正在寻找一种特定types的控制,你可以使用像这样的recursion循环 – http://weblogs.asp.net/eporter/archive/2007/02/24/asp-net-findcontrol-recursive-with -generics.aspx

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

 /// <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); } } } } 

这可能有帮助。

 public static class ControlExtensions { /// <summary> /// recursively finds a child control of the specified parent. /// </summary> /// <param name="control"></param> /// <param name="id"></param> /// <returns></returns> public static Control FindControlRecursive(this Control control, string id) { if (control == null) return null; //try to find the control at the current level Control ctrl = control.FindControl(id); if (ctrl == null) { //search the children foreach (Control child in control.Controls) { ctrl = FindControlRecursive(child, id); if (ctrl != null) break; } } return ctrl; } } public void Page_Load(object sender, EventArgs e) { //call the recursive FindControl method Control ctrl = this.FindControlRecursive("my_control_id"); } 

像往常一样迟到。 如果有人仍然对此感兴趣,有一些相关的SO 问题和答案 。 我的版本的recursion扩展方法来解决这个问题:

 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; } } } } 

所有突出显示的解决scheme都使用recursion(这是性能成本高昂)。 这是没有recursion的更清洁的方式:

 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); } 

FindControl不会在嵌套控件内recursionsearch。 它只发现控件是NamigContainer是你调用FindControl的控件。

Theres原因ASP.Net不会查看您的嵌套控件recursion默认情况下:

  • 性能
  • 避免错误
  • 可重用性

考虑你想封装你的GridViews,Formviews,UserControls等在其他用户控件内的可重用性的原因。 如果你已经实现了页面中的所有逻辑,并通过recursion循环来访问这些控件,那么很难重构它。 如果您已经通过事件处理程序(GridView的RowDataBound)实现了您的逻辑和访问方法,那么它会更简单,更容易出错。

控制措施的行动pipe理

在基类中创build下面的类。 类获取所有控件:

 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; } } 

从数据库:获取所有操作ID(如divAction1,divAction2 ….)在DATASET(DTActions)dynamic允许特定用户。

在Aspx:在HTML中把行动(button,锚点等)在div或跨度,并给他们的ID像

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

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

 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; } } } } 

本文介绍如何按typesrecursion地查找控件,但是它的实现包含导致失去“创build”控件的一个缺陷

以下是介绍的固定版本:

  /// <summary> /// Find control (recursively) by type /// (http://weblogs.asp.net/eporter/archive/2007/02/24/asp-net-findcontrol-recursive-with-generics.aspx) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="controls"></param> /// <returns></returns> public static T FindControl<T>(System.Web.UI.ControlCollection controls) where T : class { T found = default(T); if (controls != null && controls.Count > 0) { for (int i = 0; i < controls.Count; i++) { if (found != null) break; if (controls[i] is T) { found = controls[i] as T; break; } found = FindControl<T>(controls[i].Controls); } } return found; } 

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

  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"); 

我决定只是build立控制字典。 难以维护,可能会比recursion的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的问题之前,

问:现在,我的问题是,是否有任何其他方式/解决scheme来findASP.NET中的嵌套控件? 答:是的,首先避免需要search它们。 为什么要search你已经知道的东西在那里? 最好build立一个允许参考 已知对象的系统。

以下示例定义了一个Button1_Click事件处理程序。 当被调用时,该处理程序使用FindControl方法在包含页面上定位具有TextBox2的ID属性的控件。 如果find该控件,则使用Parent属性确定其父项,并将父控件的ID写入该页面。 如果没有findTextBox2,则将“未find控件”写入页面。

 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"); } }