D
DCW
I am trying to build a Templated Control in which any number of templates may
be defined and parsed at runtime, but will allow me to define multiple
controls with the same server-side id. The number of templates is not known,
but may be 1 to “n.†The control would behave similarly to the MultiView
control, in which an active view is identified through an ActiveViewIndex
property. Therefore, even if there are multiple templates defined, only one
would ever be loaded into the control hierarchy and rendered.
Here is the markup that I am trying to achieve:
<cic:TemplatedMultiView ID="hi" runat="server" ActiveViewIndex="1">
<EditTemplate>
<asp:Label ID="Label1" runat="server" Text="View
1"></asp:Label>
</EditTemplate>
<EditTemplate>
<asp:Label ID="Label1" runat="server" Text="View
2"></asp:Label>
</EditTemplate>
<EditTemplate>
<asp:Label ID="Label1" runat="server" Text="View
3"></asp:Label>
</EditTemplate>
</cic:TemplatedMultiView>
And here is the Control code:
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
<ControlBuilder(GetType(ViewTemplateControlBuilder))> _
<ParseChildren(GetType(ViewTemplate))> _
Public Class TemplatedMultiView
Inherits CompositeControl
Implements INamingContainer
Private _viewTemplatesCollection As List(Of ITemplate) = Nothing
Private _activeViewIndex As Integer = 0
Private _editTemplate As ViewTemplate
Public Property ActiveViewIndex() As Integer
Get
Return _activeViewIndex
End Get
Set(ByVal value As Integer)
_activeViewIndex = value
End Set
End Property
Protected Overrides Sub AddParsedSubObject(ByVal obj As Object)
If TypeOf (obj) Is ITemplate Then
ViewTemplates.Add(obj)
End If
End Sub
Public Overridable ReadOnly Property ViewTemplates() As List(Of ITemplate)
Get
If (Me._viewTemplatesCollection Is Nothing) Then
Me._viewTemplatesCollection = New List(Of ITemplate)
End If
Return Me._viewTemplatesCollection
End Get
End Property
<PersistenceMode(PersistenceMode.InnerProperty)> _
<TemplateInstance(TemplateInstance.Single)> _
<TemplateContainer(GetType(TemplatedMultiView))> _
Public Property EditTemplate() As ViewTemplate
Get
Return _editTemplate
End Get
Set(ByVal value As ViewTemplate)
_editTemplate = value
End Set
End Property
Protected Overrides Sub CreateChildControls()
Controls.Clear()
Dim I As New TemplateItem()
Dim _template As ITemplate = ViewTemplates(_activeViewIndex)
_template.InstantiateIn(New TemplateItem())
ViewTemplates.Clear()
Me.Controls.Add(_template)
Me.ChildControlsCreated = True
End Sub
Protected Overrides Sub RenderContents(ByVal writer As
System.Web.UI.HtmlTextWriter)
For Each ctl As Control In Me.Controls
ctl.RenderControl(writer)
Next
End Sub
End Class
Public Class ViewTemplateControlBuilder
Inherits ControlBuilder
Public Overrides Function GetChildControlType(ByVal tagName As String,
ByVal attributes As IDictionary) As Type
If tagName.ToLower() = "edittemplate" Then
Return GetType(ViewTemplate)
End If
Return Nothing
End Function
End Class
Public Class TemplateItem
Inherits WebControl
Implements INamingContainer
End Class
<ParseChildren(False)> _
<PersistChildren(False)> _
Public Class ViewTemplate
Inherits WebControl
Implements ITemplate
Implements INamingContainer
Public Sub InstantiateIn(ByVal container As System.Web.UI.Control)
Implements System.Web.UI.ITemplate.InstantiateIn
container.Controls.Add(Me)
End Sub
End Class
Here is the error that is received, when ASP.NET tries to parse the markup:
The ID 'Label1' is already used by another control.
One suspected issue is that inside the ViewTemplateControlBuilder when there
is a breakpoint placed inside of the GetChildControlType, an interrogation of
the NamingContainerType returns the ASP.NET page. This makes sense that
ASP.NET would view the separate instances of the controls with the id of
“Label1†as duplicate controls. How do I get he NamingContainerType to be the
actual ViewTemplate for the instantiation of the individual controls?
be defined and parsed at runtime, but will allow me to define multiple
controls with the same server-side id. The number of templates is not known,
but may be 1 to “n.†The control would behave similarly to the MultiView
control, in which an active view is identified through an ActiveViewIndex
property. Therefore, even if there are multiple templates defined, only one
would ever be loaded into the control hierarchy and rendered.
Here is the markup that I am trying to achieve:
<cic:TemplatedMultiView ID="hi" runat="server" ActiveViewIndex="1">
<EditTemplate>
<asp:Label ID="Label1" runat="server" Text="View
1"></asp:Label>
</EditTemplate>
<EditTemplate>
<asp:Label ID="Label1" runat="server" Text="View
2"></asp:Label>
</EditTemplate>
<EditTemplate>
<asp:Label ID="Label1" runat="server" Text="View
3"></asp:Label>
</EditTemplate>
</cic:TemplatedMultiView>
And here is the Control code:
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
<ControlBuilder(GetType(ViewTemplateControlBuilder))> _
<ParseChildren(GetType(ViewTemplate))> _
Public Class TemplatedMultiView
Inherits CompositeControl
Implements INamingContainer
Private _viewTemplatesCollection As List(Of ITemplate) = Nothing
Private _activeViewIndex As Integer = 0
Private _editTemplate As ViewTemplate
Public Property ActiveViewIndex() As Integer
Get
Return _activeViewIndex
End Get
Set(ByVal value As Integer)
_activeViewIndex = value
End Set
End Property
Protected Overrides Sub AddParsedSubObject(ByVal obj As Object)
If TypeOf (obj) Is ITemplate Then
ViewTemplates.Add(obj)
End If
End Sub
Public Overridable ReadOnly Property ViewTemplates() As List(Of ITemplate)
Get
If (Me._viewTemplatesCollection Is Nothing) Then
Me._viewTemplatesCollection = New List(Of ITemplate)
End If
Return Me._viewTemplatesCollection
End Get
End Property
<PersistenceMode(PersistenceMode.InnerProperty)> _
<TemplateInstance(TemplateInstance.Single)> _
<TemplateContainer(GetType(TemplatedMultiView))> _
Public Property EditTemplate() As ViewTemplate
Get
Return _editTemplate
End Get
Set(ByVal value As ViewTemplate)
_editTemplate = value
End Set
End Property
Protected Overrides Sub CreateChildControls()
Controls.Clear()
Dim I As New TemplateItem()
Dim _template As ITemplate = ViewTemplates(_activeViewIndex)
_template.InstantiateIn(New TemplateItem())
ViewTemplates.Clear()
Me.Controls.Add(_template)
Me.ChildControlsCreated = True
End Sub
Protected Overrides Sub RenderContents(ByVal writer As
System.Web.UI.HtmlTextWriter)
For Each ctl As Control In Me.Controls
ctl.RenderControl(writer)
Next
End Sub
End Class
Public Class ViewTemplateControlBuilder
Inherits ControlBuilder
Public Overrides Function GetChildControlType(ByVal tagName As String,
ByVal attributes As IDictionary) As Type
If tagName.ToLower() = "edittemplate" Then
Return GetType(ViewTemplate)
End If
Return Nothing
End Function
End Class
Public Class TemplateItem
Inherits WebControl
Implements INamingContainer
End Class
<ParseChildren(False)> _
<PersistChildren(False)> _
Public Class ViewTemplate
Inherits WebControl
Implements ITemplate
Implements INamingContainer
Public Sub InstantiateIn(ByVal container As System.Web.UI.Control)
Implements System.Web.UI.ITemplate.InstantiateIn
container.Controls.Add(Me)
End Sub
End Class
Here is the error that is received, when ASP.NET tries to parse the markup:
The ID 'Label1' is already used by another control.
One suspected issue is that inside the ViewTemplateControlBuilder when there
is a breakpoint placed inside of the GetChildControlType, an interrogation of
the NamingContainerType returns the ASP.NET page. This makes sense that
ASP.NET would view the separate instances of the controls with the id of
“Label1†as duplicate controls. How do I get he NamingContainerType to be the
actual ViewTemplate for the instantiation of the individual controls?