【问题标题】:Better way to find control in ASP.NET在 ASP.NET 中查找控件的更好方法
【发布时间】:2011-06-24 18:07:10
【问题描述】:

我有一个复杂的 asp.net 表单,在一个表单中甚至有 50 到 60 个字段,例如 Multiview,在 MultiView 中我有一个 GridView,在 GridView 中我有几个 CheckBoxes

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

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

【问题讨论】:

  • 在这种情况下链接是什么意思? FindControl 只在其 NamingContainer 内找到控件,因此如果您使用 Page.FindControl,您将不会在 GridView 内找到控件,而只能找到属于页面的 NamingContainer 的控件。没有用于查找嵌套控件的递归检查。

标签: asp.net findcontrol


【解决方案1】:

如果您正在寻找一种特定类型的控件,您可以使用像这样的递归循环 - 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);
            }
        }
    }
}

【讨论】:

  • 我在 C# 代码中看到了很多。为什么在 FoundControls Get 属性中返回 IEnumerable,为什么 _foundControls 在这个类中总是一个 List?我的意思是,我知道 List 实现了 IEnumerable,但是有什么好处呢?一定有一些,因为正如我所说,我经常看到这种模式。谢谢
  • 很棒的代码,非常感谢。我曾尝试自己写这种东西,但得到了一个难看的意大利面条球。这好多了。 @MassStrike,如果您使用最通用的类​​型,则您的代码更具可移植性。这是一个很好的习惯,这就是为什么你到处都能看到它的原因。
  • 警告:给定的解决方案一开始对我不起作用,因为它从来没有指责过同一类型。 我认为如果 childControl 是用户控件,GetType() 是不够的。 childControl.GetType().BaseType 确实为我工作。希望它可以帮助别人。尽管如此,感谢@Jimmy 的解决方案:)
  • 非常感谢臭猫的评论!是的,使用 .BaseType 为用户控件带来了天壤之别。
【解决方案2】:

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

默认情况下,ASP.Net 不会递归查看嵌套控件的原因:

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

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

【讨论】:

  • 在可重用性的情况下,UserControls 可以公开一个调用自身递归方法的方法,并且这种方法提供的易用性远远超过了任何性能问题。当然,如果有数千个控件,但事实并非如此。只需询问您的客户,完美的设计广告是否对他们的业务有价值。我只想说保持简单。
【解决方案3】:

像往常一样迟到。如果有人仍然对此感兴趣,那么有许多相关的 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;
            }
        }
    }
}

【讨论】:

  • @Gaolai Peng 怎么不行?我在很多地方都使用了这个例程,并且没有遇到任何问题。
  • 这个方法好像在grandChild的后代中找不到T类型的控件。它只停在grandChild。我说的对吗?
  • 不,它会递归调用自身来遍历控件树。参考 child.FindControlsOfType()
  • 需要注意的是这个方法必须在一个静态类中,因为它为Control类型创建了一个扩展方法。否则你会得到这个编译错误:“Extension method must be defined in a non-generic static class.”
  • 我知道这是旧的,但希望有人仍然会看到这个。这可以用来查找嵌入在面板中的动态创建的网格视图吗?如果是,你会怎么称呼这个方法?
【解决方案4】:

控件上的操作管理

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

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>

在 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】:

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

        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】:

      所有突出显示的解决方案都使用递归(这会导致性能损失)。这是没有递归的更干净的方法:

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

      【讨论】:

      • 我确实花了一些时间来理解你在那里做了什么,但现在......它很漂亮!我会尽量记住...谢谢!
      【解决方案7】:

      我决定只构建控件字典。更难维护,可能比递归 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 中找到嵌套控件? A:是的,首先避免搜索它们的需要。为什么要搜索你已经知道的东西?最好构建一个允许已知对象引用的系统。

      【讨论】:

        【解决方案8】:

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

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

        【讨论】:

          【解决方案9】:

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

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

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

          【讨论】:

            猜你喜欢
            • 2010-12-31
            • 1970-01-01
            • 1970-01-01
            • 2011-05-20
            • 2012-01-16
            • 2014-01-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多