Loading Templates at Runtime in the CSK
page 1 of 1
Published: 24 Sep 2003
Unedited - Community Contributed
Abstract
Dynamically loading item templates into your templated controls can give you a lot of power when it comes to providing a customized interface. This article covers how to do this using the Community Starter Kit.
by Darren Neimke
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 8979/ 15

Last Christmas I really needed to get away from it all, just me, my wife, the beach, my laptop, and a few thousand lines of code. So we packed up the car, printed out the source to most of the Community Starter Kit, and headed to the family beach retreat--cool! The Community Starter Kit is very cool, and I'd like to thank Microsoft and Stephen Walther for putting it together and supporting it via the forums; that code has been very good to me as I've managed to resale many of the concepts from within it.

One of the most notable features is the fact that the entire application is skinnable. You can create custom skins for the application with a relatively minor amount of skill. One of the best things that I learned from that app was that you can load templates into templated controls at runtime. Let me explain!

Create a new project and add a web form named DynamicTemplates.aspx.  Inside of the form tags add the following declaration for a Repeater control:

    <asp:Repeater ID="stampsRepeater" Runat="server" />

This repeater will display a listing of stamps, so create a definition for a stamp class:

    Public Class Stamp
        Private mTitle, mImagePath As String
        Private mWidth, mHeight, mYearOfRelease As Integer
        Public ReadOnly Property Title() As String
            Get
                Return mTitle
            End Get
        End Property
        Public ReadOnly Property Width() As Integer
            Get
                Return mWidth
            End Get
        End Property
        Public ReadOnly Property Height() As Integer
            Get
                Return mHeight
            End Get
        End Property
        Public ReadOnly Property YearOfRelease() As Integer
            Get
                Return mYearOfRelease
            End Get
        End Property
        Public ReadOnly Property ImagePath() As String
            Get
                Return mImagePath
            End Get
        End Property
        Public Sub New( _
            ByVal title As String, _
            ByVal w As Int32, ByVal h As Int32, _
            ByVal year As Integer, _
            ByVal path As String _
        )
            Me.mTitle = title
            Me.mWidth = w
            Me.mHeight = h
            Me.mYearOfRelease = year
            Me.mImagePath = path
        End Sub
    End Class

In the DynamicTemplates.aspx Page_Load event handler, create a few instances of stamps and bind them to the repeater:

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles MyBase.Load
        Dim arr As New ArrayList
        Dim sTitles() As String = {"StampA", "StampB", "StampC", "StampD", "StampE"}
        Const width As Int32 = 60
        Const height As Int32 = 100
        Dim years() As Integer = {1962, 1984, 1933, 1977, 1947}
        For i As Integer = 0 To 4
            Dim st As New Stamp( _
                sTitles(i), _
                width, height, _
                years(i), _
                sTitles(i) & ".gif" _
             )
            arr.Add(st)
        Next
        stampsRepeater.DataSource = arr
        stampsRepeater.DataBind()
    End Sub

If you build the assembly and browse to the page now, you will get an empty screen--duh! Time to add some templates. Under the project root add a folder named "UserControls" and add the following three user controls:

StampsHeader.ascx

<%@ Control  %>
<table width="300" border="0" cellpadding="12" cellspacing="0">
    <tr bgcolor="DarkMagenta">
        <th colspan="2">
            <strong color="#ffffff">
                Great Stamps of our time!
            </font>
        </th>
    </tr>

StampsItem.ascx

<%@ Control %>
<tr valign="top">
    <td>
        <%# DataBinder.Eval( CType( Container, RepeaterItem ).DataItem, "Title" ) %>
        ( <%# DataBinder.Eval( CType( Container, RepeaterItem ).DataItem, "YearOfRelease" ) %> )
    </td>
    <td>
        <img 
            src="<%# DataBinder.Eval( CType( Container, RepeaterItem ).DataItem, "ImagePath" ) %>"
            width="<%# DataBinder.Eval( CType( Container, RepeaterItem ).DataItem, "Width" ) %>"
            height="<%# DataBinder.Eval( CType( Container, RepeaterItem ).DataItem, "Height" ) %>"
         />
    </td>
</tr>

StampsFooter.ascx

<%@ Control %>
    <tr bgcolor="DarkMagenta">
        <td colspan="2">&nbsp;</td>
    </tr>
</table>

Notice that in the Item.ascx template I first cast the Container item to a RepeaterItem before accessing the DataItem. Now, back in DynamicTemplates.aspx, add some more code to dynamically load the template controls into the repeater control:

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles MyBase.Init
        stampsRepeater.HeaderTemplate = LoadTemplate(Request.ApplicationPath & _
          "/UserControls/StampsHeader.ascx")
        stampsRepeater.ItemTemplate = LoadTemplate(Request.ApplicationPath & _
          "/UserControls/StampsItem.ascx")
        stampsRepeater.FooterTemplate = LoadTemplate(Request.ApplicationPath & _
          "/UserControls/StampsFooter.ascx")
    End Sub

Recompile the code and rerun the app; you are now presented with a listing of stamps laid out as described in the user controls.

One little gotcha when using dynamically loaded templates is that, if you need to do a FindControl in ItemDataBound to get an instance of a control in the template you need to make the call on Controls(0) of the e.Item--as opposed to doing it directly on the e.Item. Here's an example of that, first, I'll modify the footer control to add a Label control:

<%@ Control %>

    <tr bgcolor="DarkMagenta">
        <td colspan="2">
            <asp:Label ID="recordCountLabel" Runat="server" />
        </td>
    </tr>
</table>

Finally, add the code in the hosting page (DynamicTemplates.aspx) to find the Label and alter the Text property:

    Private Sub stampsRepeater_ItemDataBound(ByVal sender As Object, _
        ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) _
        Handles stampsRepeater.ItemDataBound
        If e.Item.ItemType = ListItemType.Footer Then
            Dim recs As Integer = CType(stampsRepeater.DataSource, ArrayList).Count
            Dim lbl As Label = CType(e.Item.Controls(0).FindControl("recordCountLabel"), Label)
            lbl.Text = recs.ToString() & " stamps are shown here."
        End If
    End Sub

Dynamically loading controls in this manner allows you to create templates that are distinct in layout and appearance and load them based on settings known only at runtime. This technique can allow your repeater controls to take on a "skinnable" behaviour based on user settings, for example, imagine if we had created several distinct sets of templates and given them themed names such as:

    StampsHeader_Forest.ascx, StampsHeader_Ocean.ascx, StampsHeader_Lunar.ascx
StampsItem_Forest.ascx, StampsItem_Ocean.ascx, StampsItem_Lunar.ascx
StampsFooter_Forest.ascx, StampsFooter_Ocean.ascx, StampsFooter_Lunar.ascx

These controls could then be loaded based on a user's stored preference to provide a completely customized look and feel to your pages, as in the concluding example below.

    Dim cookie As HttpCookie = Request.Cookies("ThemeName")
    Dim themeName As String = "Forest"
    If Not cookie Is Nothing Then
        themeName = Request.Cookies("ThemeName").Value
    Else
        Response.Cookies("ThemeName").Value = "Forest"
    End If
    stampsRepeater.HeaderTemplate = _
        LoadTemplate(Request.ApplicationPath & _
          "/UserControls/StampsHeader_" & themeName & ".ascx")
    stampsRepeater.ItemTemplate = _
        LoadTemplate(Request.ApplicationPath & _
          "/UserControls/StampsItem_" & themeName & ".ascx")
    stampsRepeater.FooterTemplate = _
        LoadTemplate(Request.ApplicationPath & _
          "/UserControls/StampsFooter_" & themeName & ".ascx")


User Comments

Title: Thanks   
Name: Suba
Date: 2006-06-11 7:47:22 PM
Comment:
Very informative.
Title: is it possible to use templates per row?   
Name: DiAbLo34
Date: 2005-05-06 2:39:42 PM
Comment:
First of all, great article! :) it is very useful, but i was wondering if there is a way to use different templates per row...
Title: Thanks for the article   
Name: Peter Mel
Date: 2004-06-14 1:24:14 AM
Comment:
Very useful!

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-25 6:10:20 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search