Dynamic Templates for the Repeater, DataList and DataGrid Controls (cont'd)

However, there is still a thing you may argue about: with this method the template is read from file every time the page loads. Even if this I/O operation shouldn’t impact on performances, we can improve the way the template is loaded, by loading it from file just the first time the template is required, and storing it into the cache for future uses. Here’s a function that does what described:


Private Function GetTemplate(ByVal templateFile As String) As ITemplate
   ' if the file has been already loaded and saved into the cache,
   ' load it  from there
   If Not Cache(templateFile) Is Nothing Then
      Trace.Write("Template " & templateFile & " loaded from cache")
      Return CType(Cache(templateFile), ITemplate)
   Else
      ' otherwise load the template file...
      Dim template As ITemplate = Page.LoadTemplate(templateFile)
      ' ...and save it into the cache, with a   dependency to the original 
      ' file, so that if the file is modified the cache  item is  removed
      Cache.Insert(templateFile, template, _
         New Caching.CacheDependency(Server.MapPath(templateFile)))
      Trace.Write("Template " & templateFile & " loaded from file")
      Return template
   End If
End Function
advertisement

When inserting the loaded template into the Cache collection we add a dependency to the source template file, so that if it is updated, the cached template is discarded, and the fresh version is loaded at the next page load. The Page.LoadMethod call used above can now be replaced as follows:

Datalist1.ItemTemplate = GetTemplate("DataList_TemplateEx.ascx")

To check whether the template is actually loaded from the cache from the second time the page is loaded, do the following:

1)       Enable the tracing by setting to true the enabled attribute of the trace tag in the Web.Config file.

2)       Refresh the page a couple of times

3)       Point the browser to trace.axd, and you’ll get a list of links to see the tracing details of each page execution. In these details pages you’ll actually see the trace messages that confirm the fact that the template has been cached and reused since the second page execution.

The figure below shows two partial screenshot from the two details pages in question:

So far I’ve shown examples with the DataList only. Working with the Repeater and the DataGrid is very similar though. To dynamically load templates in a DataGrid, you must use TemplateColumn columns, left empty as shown in the following code:


<asp:DataGrid runat="server" ID="Datagrid1"
   AutoGenerateColumns="False" Width="100%"
   ItemStyle-BackColor="LightCyan"
   ItemStyle-ForeColor="DarkBlue"        
   AlternatingItemStyle-BackColor="LightYellow"
   AlternatingItemStyle-ForeColor="Maroon"
   ...other style formatting...>
   <Columns>
      <asp:BoundColumn DataField="EmployeeID" HeaderText="ID"
         ItemStyle-Width="20" ItemStyle-BackColor="LightGreen" />          
      <asp:TemplateColumn HeaderText="Employee Info" />
   </Columns>
</asp:DataGrid>

All you would need to change in the template file is the cast: in this case you must cast the Container object to the DataGridItem type not to DataListItem because that is the type of the DataGrid's items. The same would be for a Repeater, you would have to cast to a RepeaterItem. In the sample code provided as a separate download for this article, you can find full examples for all these controls. The code below instead is the complete implementation for the Page_Load event, that show how it’s actually the same to load a template for a Repeater and a DataList, and also for a DataGrid, once we have a reference to its template column that we want to use as container for the template:


Private Sub Page_Load() Handles MyBase.Load
   ' show the welcome message with the current username
   UserName.Text = User.Identity.Name.Substring( _
      User.Identity.Name.IndexOf("\") + 1)
   ' get a  reference to the DataGrid’s template column
   Dim templCol As TemplateColumn  = CType( _
      Datagrid1.Columns(1), TemplateColumn)
   ' load the proper templates according to the logged-in user
   If User.IsInRole("BUILTIN\Administrators") Then
      Repeater1.ItemTemplate = GetTemplate("Repeater_TemplateEx.ascx")
      Datalist1.ItemTemplate = GetTemplate("DataList_TemplateEx.ascx")
      templCol.ItemTemplate = GetTemplate("DataGrid_TemplateEx.ascx")
   Else
      Repeater1.ItemTemplate = GetTemplate("Repeater_TemplateSimple.ascx")
      Datalist1.ItemTemplate = GetTemplate("DataList_TemplateSimple.ascx")
      templCol.ItemTemplate = GetTemplate("DataGrid_TemplateSimple.ascx")
   End If
   BindControls()
End Sub

The BindControls method takes care of retrieving the data to show from the database, and bind it to the template controls. It uses a DataSet instead of a DataReader, because the data must be bound to three controls, so it makes perfect sense to retrieve the data only once and then use it for multiple controls:


Private Sub BindControls()
   ' fill a DataSet's DataTable with all the data from 
   ' the Northwind's Employees table
   Dim cn As New SqlConnection( _
      ConfigurationSettings.AppSettings("NWConnString"))
   Dim cmd As New SqlCommand("SELECT * FROM Employees", cn)
   Dim ds As New DataSet()
   Dim da As New SqlDataAdapter(cmd)
   da.Fill(ds, "Employees")
   ' bind that table to all the template-based  controls
   Repeater1.DataSource = ds.Tables("Employees")
   Repeater1.DataBind()
   Datalist1.DataSource = ds.Tables("Employees")
   Datalist1.DataBind()
   Datagrid1.DataSource = ds.Tables("Employees")
   Datagrid1.DataBind()
End Sub
Previous Page: Introduction Next Page: Custom Template Classes


Page 1: IntroductionPage 3: Custom Template Classes
Page 2: Loading the TemplatePage 4: Using the Class