在嵌套母版页中查找控件

时间:2009-04-08 01:15:23

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

我有一个嵌套2级的母版页。它有一个母版页,该母版页有一个母版页。

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

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

我完全失去了吗?或者这是如何完成的?

我即将使用MultiView,它位于条件内容控件中。所以,如果我想要更改视图,我必须获得对该控件的引用吗?得到这个参考将更加肮脏!还有更好的方法吗?

由于

6 个答案:

答案 0 :(得分:23)

查找控件很痛苦,我一直在使用这个方法,这是我很久以前从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 :(得分:4)

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

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

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

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

C#:

this.Page;

VB.NET

Me.Page

我发现通常,Control的类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

答案 2 :(得分:4)

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

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

我不是百分百肯定,但我认为这对于嵌套母版页来说会更简单,因为您只需将VirtualPath指向包含您希望访问的控件的母版。如果你想访问两个控件,每个相应的母版页中都有一个控件,这可能会很棘手。

答案 3 :(得分:2)

这是一个更通用的代码,可以使用自定义条件(可以是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;
    }
}

答案 4 :(得分:1)

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

我在主母版页中有这个

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


    }

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

然后在细节大师中我有这个

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

    }

我从详细信息主机调用主要主属性来创建相同的行为。

答案 5 :(得分:0)

我让它完美运作。

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

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