Reputation: 19953
Before I start, I am not asking how to access a server-side control hosted within a UserControl from the parent page. That's been asked many times, and this is not a duplicate of that.
This question is about server-side controls placed within a template item of a UserControl instance.
In ASP.NET I have a UserControl with multiple template handlers, which results in an HTML block being rendered with a single instance of each template (it is not like a <asp:Repeater>
where a template is used multiple times). For example:
<uc1:MyUserControl runat="server" ID="myCtrl1">
<TopControls>
<asp:Literal runat="server" ID="litTop" />
</TopControls>
<BottomControls>
<asp:Button runat="server" id="btnBottom" />
</BottomControls>
</uc1:MyUserControl>
And the UserControl is set up something like...
<div class="myUserControl">
<div class="topControls">
<asp:PlaceHolder runat="server" id="plhTopControls" />
</div>
<div class="bottomControls">
<asp:PlaceHolder runat="server" id="plhBottomControls" />
</div>
</div>
The problem is that in order for the parent page to access the controls, it's necessary for me to have a method in the UserControl to find them:
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
This is because the Visual Studio 2015 designer no longer sees the two server-side controls as belonging to the page, but instead the controls belong to the UserControl, and so I have to specifically declare them in the page and set them up in the Page_Load
:
Protected WithEvents litTop as Literal
Protected WithEvents btnBottom as Button
litTop = myCtrl1.FindControl("litTop")
btnBottom = myCtrls.FindControl("btnBottom")
Is it possible to set up the UserControl so that the server-side controls within the templates are picked up by the designer file for the parent page, so I don't have to go through this each time I add a new UserControl or server-side control within that UserControl?
If it is not possible with a UserControl, is it possible to do it with a server-side control? (If so, what attributes are required for that?)
Upvotes: 1
Views: 725
Reputation: 55409
In MyUserControl.ascx.vb, decorate the ITemplate properties with TemplateInstanceAttribute, specifying TemplateInstance.Single. (The default is Multiple.) From the documentation:
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; }
After you compile the code and re-save the parent page, the Visual Studio designer will generate backing fields for controls declared inside the templates.
Note: You should only specify TemplateInstance.Single if the template is instantiated exactly once.
Upvotes: 3