How can I render content from an aspx page in a custom control

271 views Asked by At

I am writing a composite control that should render any content placed between it's opening and closing tag in the consuming aspx page.

VB

Public Class MyComposite
    Inherits CompositeControl
    Implements INamingContainer

    Public Property UserContentTemplate as ITemplate = Nothing

    Public Overrides ReadOnly Property Controls() As ControlCollection
        Get
            EnsureChildControls()
            Return MyBase.Controls
        End Get
    End Property

    Protected Overrides Sub CreateChildControls()
        ' This is where I'm creating the controls
        ' for the composite
    End Sub

    Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
        ' This is where I render the composite controls
    End Sub

    Protected Overrides Sub RecreateChildControls()
        EnsureChildControls()
    End Sub

    Public Overrides Sub DataBind()
        CreateChildControls()
        ChildControlsCreated = True
        MyBase.DataBind()
    End Sub
End Class

From here the UserContentTemplate is available in the consuming aspx page

<cc:MyComposite runat="server" ID="MyCompositeID">
    <UserContentTemplate>
        <asp:Button... />
        <asp:TextBox... />
    </UserContentTemplate>
</cc:MyComposite>

at this point, the asp:Button and asp:TextBox are not being rendered. I have checked out this link Building Templated Custom ASP.NET Serv Controls, but I don't know if this applies or how to apply it in my situation. If you look at the link, you'll see that there are HTML elements inside the <StatsTemplate> tag which are rendered in the custom control.

2

There are 2 answers

0
Mark Davich On BEST ANSWER

I found the answer here: Web Control Templates Explained written by Miguel Castro. The article helped clarify what was going on in the Microsoft article I referenced in the question.

Imports System.Web.UI
Imports System.Web.UI.WebControls

Public Class MyTemplate
    Inherits CompositeControl
    Implements INamingContainer
End Class

Public Class MyComposite
    Inherits CompositeControl
    Implements INamingContainer

    <
        TemplateContainer(GetType(MyTemplate)),
        PersistenceMode(PersistenceMode.InnerProperty)
    > _
    Public Property UserContentTemplate as ITemplate = Nothing

    Public Overrides ReadOnly Property Controls() As ControlCollection
        Get
            EnsureChildControls()
            Return MyBase.Controls
        End Get
    End Property

    Protected Overrides Sub CreateChildControls()
        ' I prepend the template to the Controls collection
        If UserContentTemplate IsNot Nothing Then
            Dim template = New MyTemplate()
            UserContentTemplate.InstantiateIn(template)
            Controls.Add(template)
        End If
 
        ' Create and add other controls here
    End Sub

    Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
        ' This is where I render the composite controls
        writer.AddAttribute(HtmlTextWriterAttribute.Class, "my-class")
        writer.RenderBeginTag(TagKey)

        For Each ctl As Control In Controls
            ctl.RenderControl(writer)
        Next

        writer.RenderEndTag()
    End Sub

    Protected Overrides Sub RecreateChildControls()
        EnsureChildControls()
    End Sub
End Class

Main Points

  1. Create a class (MyTemplate) that inherits from CompositeControl and implements INamingContainer
  2. Decorate the UserContentTemplate with TemplateContainer attribute of type MyTemplate
  3. Instantiate the UserContentTemplate in CreateChildControls
  4. Render all the controls in the Render override
  5. Remove the DataBind override, I didn't need it in my case

The UserContentTemplate is instantiated as soon as the UserContentTemplate tag is used in the aspx page.

<cc:MyComposite runat="server" ID="MyCompositeID">
    <UserContentTemplate>
        <asp:Button... />
        <asp:TextBox... />
    </UserContentTemplate>
</cc:MyComposite>

The code in this answer solves the issue of being able to render consumer (developer) content in a composite control using Templates.

1
Chris Berlin On

HTML of The following function returns the HTML of rendered control.

You can use a placholder, to add all controls for rendering and pass the Placeholder to the function or you can pass your control directly.

 Public Function RenderUserControlToString(ByRef WebControl As Control) As String

        Dim sb As StringBuilder = New StringBuilder
        Dim sw As StringWriter = New StringWriter(sb)
        Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
        Try
            WebControl.RenderControl(htw)
        Catch ex As Exception
            sb.Append(ex.Message & vbCrLf & ex.StackTrace)
        End Try
        Return sb.ToString()
    End Function