【问题标题】:Finding controls inside nested master pages在嵌套母版页中查找控件
【发布时间】:2010-10-18 05:01:05
【问题描述】:

我有一个嵌套 2 层的母版页。它有一个母版页,而那个母版页也有一个母版页。

当我将控件粘贴到名为“bcr”的 ContentPlaceHolder 中时 - 我必须像这样找到控件:

 Label lblName =(Label)Master.Master.FindControl("bcr").FindControl("bcr").FindControl("Conditional1").FindControl("ctl03").FindControl("lblName");

我完全迷路了吗?还是需要这样做?

我即将使用 MultiView,它位于条件内容控件内部。因此,如果我想更改视图,我必须获得对该控件的引用,对吗?获得该参考将更加糟糕!有没有更好的办法?

谢谢

【问题讨论】:

    标签: c# asp.net .net-3.5 master-pages


    【解决方案1】:

    查找控件很痛苦,我一直在使用这种方法,我很久以前从CodingHorror blog 得到的,如果传入一个空的 id,只需进行一次修改就会返回 null。

    /// <summary>
    /// Recursive FindControl method, to search a control and all child
    /// controls for a control with the specified ID.
    /// </summary>
    /// <returns>Control if found or null</returns>
    public static Control FindControlRecursive(Control root, string id)
    {
        if (id == string.Empty)
            return null;
    
        if (root.ID == id)
            return root;
    
        foreach (Control c in root.Controls)
        {
            Control t = FindControlRecursive(c, id);
            if (t != null)
            {
                return t;
            }
        }
        return null;
    }
    

    在你的情况下,我认为你需要以下内容:

    Label lblName = (Label) FindControlRecursive(Page, "lblName");
    

    使用这种方法通常更方便,因为您无需知道控件所在的确切位置即可找到它(当然,假设您知道 ID),但如果您有同名的嵌套控件,你可能会遇到一些奇怪的行为,所以这可能需要注意。

    【讨论】:

    • +1 我知道这大概是 5 岁了,但是这种方法让我省了一些麻烦,谢谢!
    【解决方案2】:

    首先,您应该知道 MasterPages 实际上位于 Pages 内部。以至于 MasterPage 的 Load 事件实际上是在 ASPX 的 Load 事件之后调用的。

    这意味着,Page 对象实际上是控件层次结构中的最高控件。

    因此,了解这一点,在这种嵌套环境中查找任何控件的最佳方法是编写一个递归函数,循环遍历每个控件和子控件,直到找到您要查找的那个。在这种情况下,您的 MasterPages 实际上是主 Page 控件的子控件。

    您可以从任何这样的控件内部访问主 Page 对象:

    C#:

    this.Page;

    VB.NET

    我的页面

    我发现控件的类 FindControl() 方法通常没什么用,因为环境总是嵌套的。

    因为如果这样,我决定使用 .NET 的 3.5 新扩展功能来扩展 Control 类。

    通过使用下面的代码 (VB.NET),例如,您的 AppCode 文件夹,您的所有控件现在将通过调用 FindByControlID() 执行递归查找

        Public Module ControlExtensions
        <System.Runtime.CompilerServices.Extension()> _
        Public Function FindControlByID(ByRef SourceControl As Control, ByRef ControlID As String) As Control
            If Not String.IsNullOrEmpty(ControlID) Then
                Return FindControlHelper(Of Control)(SourceControl.Controls, ControlID)
            Else
                Return Nothing
            End If
        End Function
    
        Private Function FindControlHelper(Of GenericControlType)(ByVal ConCol As ControlCollection, ByRef ControlID As String) As Control
            Dim RetControl As Control
    
            For Each Con As Control In ConCol
                If ControlID IsNot Nothing Then
                    If Con.ID = ControlID Then
                        Return Con
                    End If
                Else
                    If TypeOf Con Is GenericControlType Then
                        Return Con
                    End If
                End If
    
                If Con.HasControls Then
                    If ControlID IsNot Nothing Then
                        RetControl = FindControlByID(Con, ControlID)
                    Else
                        RetControl = FindControlByType(Of GenericControlType)(Con)
                    End If
    
                    If RetControl IsNot Nothing Then
                        Return RetControl
                    End If
                End If
            Next
    
            Return Nothing
        End Function
    
    End Module
    

    【讨论】:

      【解决方案3】:

      虽然我喜欢递归,并且同意 andy 和 Mun,但您可能要考虑的另一种方法是使用 strongly typed Master page。您所要做的就是在您的 aspx 页面中添加一个指令。

      考虑从页面本身访问母版页中的控件,而不是从母版页访问页面的控件。当您在母版页上有页眉标签并希望从使用母版页的每个页面中设置其值时,这种方法很有意义。

      我不能 100% 确定,但我认为这将是嵌套母版页的更简单技术,因为您只需将 VirtualPath 指向包含您希望访问的控件的母版。但是,如果您想访问两个控件,每个母版页中都有一个,这可能会很棘手。

      【讨论】:

      • 是的,好点。有时,只需将该功能放在自定义页面库中的某种方法或属性中就可以了。当然,内置递归控制查找器并没有什么坏处
      【解决方案4】:

      这是一个更通用的代码,可以使用自定义条件(可以是 lambda 表达式!)

      呼叫:

      Control founded = parent.FindControl(c => c.ID == "youdId", true);
      

      控制扩展

       public static class ControlExtensions
      {
          public static Control FindControl(this Control parent, Func<Control, bool> condition, bool recurse)
          {
              Control founded = null;
              Func<Control, bool> search = null;
              search = c => c != parent && condition(c) ? (founded = c) != null :
                                                          recurse ? c.Controls.FirstOrDefault(search) != null :
                                                          (founded = c.Controls.FirstOrDefault(condition)) != null;
              search(parent);
              return founded;
          }
      }
      

      【讨论】:

        【解决方案5】:

        我使用了&lt;%@ MasterType VirtualPath="~/MyMaster.master" %&gt; 方法。我在主母版页中有一个属性,然后在详细母版页中有其他同名的属性调用主主属性,它工作正常。

        我在主页上有这个

         public string MensajeErrorString
            {
                set
                {
                    if (value != string.Empty)
                    {
                        MensajeError.Visible = true;
                        MensajeError.InnerHtml = value;
                    }
                    else
                        MensajeError.Visible = false;
                }
        
        
            }
        

        这只是一个必须显示错误消息的 div 元素。我想在带有详细母版页的页面中使用相同的属性(这与主母版嵌套)。

        然后在detail master我有这个

          public string MensajeErrorString
            {
                set
                {
                        Master.MensajeErrorString = value;
                }
        
            }
        

        我从细节主控调用主主控属性来创建相同的行为。

        【讨论】:

          【解决方案6】:

          我刚刚让它完美运行。

          在 contentpage.aspx 中,我写了以下内容:

          If Master.Master.connectsession.IsConnected Then my coded comes in here End If

          【讨论】:

            猜你喜欢
            • 2012-06-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-05-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多