【问题标题】:ASP.Net FindControl is not working - How come?ASP.Net FindControl 不起作用 - 怎么会?
【发布时间】:2010-10-22 10:17:28
【问题描述】:

我过去使用过FindControl,在 .NET 2.0/3.0 之前。现在看来,出于某种原因,我的控件的 ID 被分配了一个时髦的名称。例如,我为复选框分配了一个 ID“cbSelect”,但 FindControl 没有找到它。当我查看 HTML 时,它被分配了ctl00_bodyPlaceHolder_ctl02_cbSelect

我还没有找到一个提到这一点的 FindControl 示例。事实上,每个人似乎都只是像平常一样使用查找控件。

那么,我做错了吗? .Net 改变了吗?谁能帮我解释一下,真是令人沮丧!

【问题讨论】:

    标签: c# .net asp.net findcontrol


    【解决方案1】:

    您可能正在使用 MasterPage 或用户控件 (ascx),这就是客户端 ID 更改的原因。假设您在母版页中有一个控件,其 id 与页面中的控件相同。这将导致冲突。 id 更改确保所有 ClientID 属性在页面上都是唯一的。

    在使用 MasterPages 时,FindControl 需要特别注意。看看ASP.NET 2.0 MasterPages and FindControl()。 FindControl 在naming container 内工作。 MasterPage 和页面是不同的命名容器。

    【讨论】:

    • 微软实现这个的方式真是个笑话,它应该可以工作。哦,你有母版页吗? 500 个嵌套母版页怎么样?该方法应该弄清楚并做必要的事情来找到控制,周期。
    • 你知道你在同一个想法中使用“应该”和“微软”吗?
    【解决方案2】:

    您可以编写扩展程序以使用递归查找页面上的任何控件。 这可能在某些 Util/Helper 类中。

     public static Control FindAnyControl(this Page page, string controlId)
        {
            return FindControlRecursive(controlId, page.Form);
        }
    
        public static Control FindAnyControl(this UserControl control, string controlId)
        {
            return FindControlRecursive(controlId, control);
        }
    
        public static Control FindControlRecursive(string controlId, Control parent)
        {
            foreach (Control control in parent.Controls)
            {
                Control result = FindControlRecursive(controlId, control);
                if (result != null)
                {
                    return result;
                }
            }
            return parent.FindControl(controlId);
        }
    

    【讨论】:

      【解决方案3】:

      在“大多数”情况下使用简单的扩展方法解决了这个问题,我很幸运

      如果您想扫描整个控件层次结构,您可以在任何您认为最好的更高级别的容器控件上调用它,包括页面本身。

      private static Control FindControlIterative(this Control control, string id)
      {
          Control ctl = control;
      
          LinkedList<Control> controls = new LinkedList<Control>();
      
          while(ctl != null)
          {
              if(ctl.ID == id)
              {
                  return ctl;
              }
      
              foreach(Control child in ctl.Controls)
              {
                  if(child.ID == id)
                  {
                      return child;
                  }
      
                  if(child.HasControls())
                  {
                      controls.AddLast(child);
                  }
              }
      
              ctl = controls.First.Value;
              controls.Remove(ctl);
          }
      
          return null;
      }
      

      【讨论】:

        【解决方案4】:

        在控件集合中搜索控件时,始终使用您分配给控件的 id,而不是您在源后渲染中看到的那个。如果 FindControl() 没有找到您知道存在的控件,则很有可能您没有在控件层次结构的右分支中进行搜索。递归函数对我来说是成功的。

        这是我用于 VB.NET 3.5 的示例:

        Function FindControlRecursive(ByVal ctrl As Control, ByVal id As String) As Control
            Dim c As Control = Nothing
        
            If ctrl.ID = id Then
                c = ctrl
            Else
                For Each childCtrl In ctrl.Controls
                    Dim resCtrl As Control = FindControlRecursive(childCtrl, id)
                    If resCtrl IsNot Nothing Then c = resCtrl
                Next
            End If
        
            Return c
        End Function
        

        以下是我将如何在我的基页类中局部实现此功能的示例:

        Dim form HtmlForm = CType(FindControlRecursive(Me, "Form"), HtmlForm)
        

        【讨论】:

        • +1 因为没有看到你的我已经用相同的方法在 C# 中实现了它:public static System.Web.UI.Control FindControlRecursive(Control ctl, string id){ if (ctl == null) return null; if (ctl.ID == id) 返回 ctl; if (ctl.Controls.Count > 0) foreach(ctl.Controls 中的控制 sc) { 控制 fnd = FindControlRecursive(sc, id);如果(fnd!= null)返回fnd; } 返回空值; }`
        【解决方案5】:

        这是对我有用的 VB.NET 代码:

        <Extension()> _
        Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
            If controlToStartWith Is Nothing Then Return Nothing
            If controlToStartWith.ID = controlIdToFind Then Return controlToStartWith
            For Each childControl As Control In controlToStartWith.Controls
                Dim resCtrl As Control = FindChildControlById(childControl, controlIdToFind)
                If resCtrl IsNot Nothing Then Return resCtrl
            Next childControl
            Return Nothing
        End Function ' Function FindChildControlById(ByVal controlToStartWith As Control, ByVal controlIdToFind As String) As Control
        

        感谢 George 的初始 VB.NET 代码。我只修改了一点点,有 2 个功能更改:如果/当 null/Nothing 作为输入控件传递时,我的不会出错,而我的作为扩展实现。我的其他 3 个小更改不会影响功能,但对我来说,它们是代码简化。但我知道这是非常主观的。

        所以这个方法可以用在:

        Dim c1 As Control = Page.FindChildControlById("aspControlID")
        

        如果你想把它转换成一个特定的控件子类,像这样:

        Dim c1 As Control = Page.FindChildControlById("aspControlID")
        Dim c As HyperLink = TryCast(c1, HyperLink)
        

        更新:我的函数现在被命名为“FindChildControlById”(以前是“FindMiControl”)。我更喜欢 SpeedNet 的建议。

        【讨论】:

        • 这很完美,比其他解决方案更好,谢谢!我重命名为 FindChildControlByID()。
        【解决方案6】:

        当它呈现 html 时,ASP.NET 将在所有控件 ID 前加上命名容器(用户控件等)的 ID,并在一个层次结构中一直追溯到文档根目录。这可确保所有 ID 对于回发等都是唯一的。

        这不会影响使用 FindControl,您应该在原始标记中使用 ID。

        【讨论】:

          【解决方案7】:

          这是关于如何命名 Web 表单控件的参考...

          Web Forms Control Identification

          【讨论】:

            猜你喜欢
            • 2012-02-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-23
            • 1970-01-01
            • 2023-03-26
            • 2012-11-02
            相关资源
            最近更新 更多