从父页面访问 UserControl 中基于模板的控件

Accessing template-based controls in UserControl from parent page

在开始之前,我不是询问如何从父页面访问 UserControl 中托管的服务器端控件。这个问题已经被问过很多次了,这不是那个的重复。

这个问题是关于放置在 UserControl 实例的 模板 项中的服务器端控件。


在 ASP.NET 中,我有一个带有多个模板处理程序的 UserControl,这导致 HTML 块使用 单个实例 呈现每个模板的(它不像 <asp:Repeater> 模板被多次使用)。例如:

<uc1:MyUserControl runat="server" ID="myCtrl1">
  <TopControls>
    <asp:Literal runat="server" ID="litTop" />
  </TopControls>
  <BottomControls>
    <asp:Button runat="server" id="btnBottom" />
  </BottomControls>
</uc1:MyUserControl>

而 UserControl 的设置类似于...

<div class="myUserControl">
  <div class="topControls">
    <asp:PlaceHolder runat="server" id="plhTopControls" />
  </div>
  <div class="bottomControls">
    <asp:PlaceHolder runat="server" id="plhBottomControls" />
  </div>
</div>

问题是,为了让 父页面 访问控件,我必须在 UserControl 中有一个方法来找到它们:

Public Overrides Function FindControl(id As String) As System.Web.UI.Control
    Dim ctrl As Control = Nothing
    If Not TopControlsContainer Is Nothing Then
        ctrl = TopControlsContainer.FindControl(id)
    End If
    If ctrl Is Nothing AndAlso Not BottomControlsContainer Is Nothing Then
        ctrl = BottomControlsContainer.FindControl(id)
    End If
    If ctrl Is Nothing Then
        ctrl = MyBase.FindControl(id)
    End If
    Return ctrl
End Function

这是因为Visual Studio2015设计器不再将这两个服务器端控件视为属于页面,而是属于UserControl,所以我必须在页面并在 Page_Load:

中设置它们
Protected WithEvents litTop as Literal
Protected WithEvents btnBottom as Button

litTop = myCtrl1.FindControl("litTop")
btnBottom = myCtrls.FindControl("btnBottom")

是否可以设置 UserControl 以便模板中的服务器端控件由父页面的设计器文件选取,所以我不这样做每次我在该 UserControl 中添加新的 UserControl 或服务器端控件时都必须执行此操作吗?

如果用 UserControl 做不到,是否可以用服务器端控件做? (如果是这样,那需要什么属性?)

在 MyUserControl.ascx.vb 中,用 TemplateInstanceAttribute, specifying TemplateInstance.Single 修饰 ITemplate 属性。 (默认为多个。)来自文档:

A single instance of a template allows you to reference controls that are contained within the template.

VB.NET:

<PersistenceMode(PersistenceMode.InnerProperty)>
<TemplateInstance(TemplateInstance.Single)>
Public Property TopControls As ITemplate

<PersistenceMode(PersistenceMode.InnerProperty)>
<TemplateInstance(TemplateInstance.Single)>
Public Property BottomControls as ITemplate

C#:

[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
public ITemplate TopControls { get; set; }

[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateInstance(TemplateInstance.Single)]
public ITemplate BottomControls { get; set; }

编译代码并重新保存父页面后,Visual Studio 设计器将为模板内声明的控件生成支持字段。

注意:如果模板仅实例化一次,您应该只指定TemplateInstance.Single。