在嵌套母版页中查找控件

时间:2022-10-19 21:36:23

I have a master page which is nested 2 levels. It has a master page, and that master page has a master page.

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

When I stick controls in a ContentPlaceHolder with the name "bcr" - I have to find the controls like so:

当我在名为“bcr”的ContentPlaceHolder中粘贴控件时 - 我必须找到如下所示的控件:

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

Am I totally lost? Or is this how it needs to be done?

我完全迷失了吗?或者这是它需要做的?

I am about to work with a MultiView, which is inside of a conditional content control. So if I want to change the view I have to get a reference to that control right? Getting that reference is going to be even nastier! Is there a better way?

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

Thanks

谢谢

6 个解决方案

#1


4  

Firstly, you should know that MasterPages actually sit inside Pages. So much so that a MasterPage's Load event is actually called after your ASPX's Load event.

首先,您应该知道MasterPages实际上位于Pages中。因此,在ASPX的Load事件之后实际调用MasterPage的Load事件。

This means, the Page object is actually the highest control in the control hierarchy.

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

So, knowing this, the best way to find any control in such a nested environment, is to write a recursive function that loops through every control and child controls until it finds the one you're looking for. in this case, your MasterPages are actually child controls of the main Page control.

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

You get to the main Page object from inside any control like this:

您可以从任何控件内部访问主Page对象,如下所示:

C#:

C#:

this.Page;

这一页;

VB.NET

VB.NET

Me.Page

Me.Page

I find that usually, the Control's class FindControl() method is pretty useless, as the enviroment is always nested.

我发现通常,Control的类FindControl()方法是无用的,因为环境总是嵌套的。

Because if this, I've decided to use .NET's 3.5 new Extension features to extend the Control class.

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

By using the code below (VB.NET), in say, your AppCode folder, all your controls will now peform a recursive find by calling FindByControlID()

通过使用下面的代码(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


22  

Finding controls is a pain, and I've been using this method which I got from the CodingHorror blog quite a while ago, with a single modification that returns null if an empty id is passed in.

查找控件很痛苦,我一直在使用这个方法,这是我很久以前从CodingHorror博客获得的,只有一个修改,如果传入一个空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;
}

In your case, I think you'd need the following:

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

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

Using this method is generally much more convenient, as you don't need to know exactly where the control resides to find it (assuming you know the ID, of course), though if you have nested controls with the same name, you'll probably get some strange behavior, so that might be something to watch out for.

使用这种方法通常要方便得多,因为你不需要确切地知道控件所在的位置(当然,假设你知道ID),但是如果你有同名的嵌套控件,你将会可能会有一些奇怪的行为,所以这可能需要注意。

#3


4  

Although I love recursion, and agree with andy and Mun, one other approach you may want to consider is to have a strongly typed Master page. All you have to do is add one directive in your aspx page.

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

Instead of accessing a page's control from your master page, consider accessing a control in your master page from the page itself. This approach makes a lot of sense when you have a header label on your master page, and want to set its value from each page that uses the master.

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

I'm not 100% sure, but I think this would be simpler technique with nested master pages, as you would just point the VirtualPath to the master containing the control you wish to access. It might prove to be tricky though if you want to access two controls, one in each respective master page.

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

#4


2  

Here is a code that is more generic and works with a custom condition (that can be a lambda expression!)

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

Call:

呼叫:

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

Control extension

控制扩展

 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


1  

I have used the <%@ MasterType VirtualPath="~/MyMaster.master" %> method. I have a property in the main master page then in the detail master page other property with the same name calling the main master property and it works fine.

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

I have this in the main master page

我在主母版页中有这个

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


    }

this is just a div element that have to show an error message. I would like to use this same property in the pages with the detail master page(this is nested with the main master).

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

Then in the detail master I have this

然后在细节大师我有这个

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

    }

Im calling the main master property from the detail master to create the same behavior.

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

#6


0  

I just got it working perfectly.

我刚刚完美地完成了它。

In contentpage.aspx, I wrote the following:

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

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

如果Master.Master.connectsession.IsConnected然后我的编码进来这里结束如果

#1


4  

Firstly, you should know that MasterPages actually sit inside Pages. So much so that a MasterPage's Load event is actually called after your ASPX's Load event.

首先,您应该知道MasterPages实际上位于Pages中。因此,在ASPX的Load事件之后实际调用MasterPage的Load事件。

This means, the Page object is actually the highest control in the control hierarchy.

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

So, knowing this, the best way to find any control in such a nested environment, is to write a recursive function that loops through every control and child controls until it finds the one you're looking for. in this case, your MasterPages are actually child controls of the main Page control.

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

You get to the main Page object from inside any control like this:

您可以从任何控件内部访问主Page对象,如下所示:

C#:

C#:

this.Page;

这一页;

VB.NET

VB.NET

Me.Page

Me.Page

I find that usually, the Control's class FindControl() method is pretty useless, as the enviroment is always nested.

我发现通常,Control的类FindControl()方法是无用的,因为环境总是嵌套的。

Because if this, I've decided to use .NET's 3.5 new Extension features to extend the Control class.

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

By using the code below (VB.NET), in say, your AppCode folder, all your controls will now peform a recursive find by calling FindByControlID()

通过使用下面的代码(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


22  

Finding controls is a pain, and I've been using this method which I got from the CodingHorror blog quite a while ago, with a single modification that returns null if an empty id is passed in.

查找控件很痛苦,我一直在使用这个方法,这是我很久以前从CodingHorror博客获得的,只有一个修改,如果传入一个空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;
}

In your case, I think you'd need the following:

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

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

Using this method is generally much more convenient, as you don't need to know exactly where the control resides to find it (assuming you know the ID, of course), though if you have nested controls with the same name, you'll probably get some strange behavior, so that might be something to watch out for.

使用这种方法通常要方便得多,因为你不需要确切地知道控件所在的位置(当然,假设你知道ID),但是如果你有同名的嵌套控件,你将会可能会有一些奇怪的行为,所以这可能需要注意。

#3


4  

Although I love recursion, and agree with andy and Mun, one other approach you may want to consider is to have a strongly typed Master page. All you have to do is add one directive in your aspx page.

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

Instead of accessing a page's control from your master page, consider accessing a control in your master page from the page itself. This approach makes a lot of sense when you have a header label on your master page, and want to set its value from each page that uses the master.

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

I'm not 100% sure, but I think this would be simpler technique with nested master pages, as you would just point the VirtualPath to the master containing the control you wish to access. It might prove to be tricky though if you want to access two controls, one in each respective master page.

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

#4


2  

Here is a code that is more generic and works with a custom condition (that can be a lambda expression!)

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

Call:

呼叫:

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

Control extension

控制扩展

 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


1  

I have used the <%@ MasterType VirtualPath="~/MyMaster.master" %> method. I have a property in the main master page then in the detail master page other property with the same name calling the main master property and it works fine.

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

I have this in the main master page

我在主母版页中有这个

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


    }

this is just a div element that have to show an error message. I would like to use this same property in the pages with the detail master page(this is nested with the main master).

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

Then in the detail master I have this

然后在细节大师我有这个

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

    }

Im calling the main master property from the detail master to create the same behavior.

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

#6


0  

I just got it working perfectly.

我刚刚完美地完成了它。

In contentpage.aspx, I wrote the following:

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

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

如果Master.Master.connectsession.IsConnected然后我的编码进来这里结束如果