在嵌套母版页中查找控件

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

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

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

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

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

谢谢

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

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

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

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

C#:

这一页;

VB.NET

Me.Page

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

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

通过使用下面的代码(VB.NET),比如你的AppCode文件夹,所有的控件现在都可以通过调用FindByControlID()来执行递归查找

  Public Module ControlExtensions  _ 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 

查找控件很痛苦,我一直在使用这个方法,这是我很久以前从CodingHorror博客获得的,只有一个修改,如果传入一个空id,则返回null。

 ///  /// Recursive FindControl method, to search a control and all child /// controls for a control with the specified ID. ///  /// Control if found or null 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),但是如果你有同名的嵌套控件,你将会可能会有一些奇怪的行为,所以这可能需要注意。

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

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

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

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

呼叫:

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

控制扩展

  public static class ControlExtensions { public static Control FindControl(this Control parent, Func condition, bool recurse) { Control founded = null; Func 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; } } 

我使用了<%@ 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; } } 

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

我刚刚完美地完成了它。

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

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