1. Technology
Binding the DataList ASP.NET Control with Dynamic Templates
Learn how to programmatically implement the ITemplate interface to dynamically create the ItemTemplate content for a DataList Web Server control.
Source Code
Download Source Code
Join the Discussion
"Post your views and comments to this chapter of the free Asp.Net Delphi Programming Course"
Discuss!
Related Resources
A Beginner's Guide to Asp.Net Programming for Delphi developers.TOC

Welcome to the 22nd chapter of the FREE online programming course:
A Beginner's Guide to Asp.Net Programming for Delphi developers.
Implementing the ITemplate interface to programmatically create data bound list control templates.

Back in the last few chapters, we've looked at several different approaches to data binding in ASP.NET web applications: binding list controls, using binding expressions and binding the Repeater control (the most lightweight of all data bound list controls).

Throughout this chapter, you'll learn about the following:

  • DataList Web Server control
  • ITemplate interface (defining programmatically)
  • NamingContainer
DataList Web Server Control
The DataList offers a richer feature set than the Repeater, including automatic generation of <table>, <tr> and <td> tags (optional) to hold each list item. DataList also requires that you create templates to define the content and layout of each item.
DataList supports 7 different templates. Beside those found in the Repeater, the DataList also provides the SelectedItemTemplate and the EditItemTemplate - to allow selecting and editing of items.
Editing and selecting in data bound list controls will be discussed when we introduce the DataGrid control.

The layout of the DataList control is controlled with the RepeatLayout property. Setting this property to RepeatLayout.Table will display the DataList in a table format, while RepeatLayout.Flow displays the DataList without a table structure.
Similar to the Repeater, the DataList, at the very minimum, needs the ItemTemplate to be defined to display "its" items.

When you drop a DataList control on a web page, at design time, you'll get the following:

DataList at design time
As the initial design time rendering of the DataList suggest, you need to specify at least the ItemTemplate for the list.

Delphi allows you to specify some of the templates visually. Right click the DataList and select "Header and Footer Templates" from the drop down list, to edit the templates.

Templates at design time

Add a hyperlink to the Footer Template (assign both the Text and the NavigateUrl properties), and a "string" to the Header Template.

DataList HeaderTemplate and FooterTemplate

Select "End Template Editing" from the right-click menu.

Note that the design time rendering of the control has not changed, however when you switch to the "aspx/html" view the asp markup will be:

<asp:DataList id="DataList1" runat="server">
<HeaderTemplate>
  About Delphi Programming
</HeaderTemplate>
<FooterTemplate>
  <asp:HyperLink 
     id="HyperLink1" 
     runat="server"
     navigateurl="http://delphi.about.com">
  delphi.about.com
  </asp:HyperLink>
</FooterTemplate>
</asp:DataList>

Note: if you run the project now, you'll get an "empty" page at run time (rendered to the user in a Web Browser). DataList will not render if the DataBind method is not called.

The DataSource
For the sake of simplicity I'll use an ArrayList variable to hold the list of custom TArticle objects that will be displayed by the DataList:

TArticle = class
private
  FTitle : string;
  FUrl : string;
public
  property Title : string read FTitle;
  property URL : string read FUrl;

  constructor Create(const title, url : string);
end;

The Page will have a property Articles (ArrayList of TArticle objects).

Here's how the Page_Load event should look:

procedure TwfDataListTemplates.Page_Load(
  sender: System.Object; 
  e: System.EventArgs);
begin
  DataList1.ItemTemplate := TDataListItemTemplate.Create;

  if NOT Page.IsPostBack then
  begin
    FillArticles;

    DataList1.DataSource := Articles;
    DataList1.DataBind;
  end;
end;

The "FillArticles" method simply places some TArticle objects in the Articles property:

procedure TwfDataListTemplates.FillArticles;
begin
  Articles.Add(TArticle.Create(
      'Display Menu Item Hints',
      '/od/vclusing/a/menuitemhints.htm'));
  Articles.Add(TArticle.Create(
      'Move and Resize Controls at Run Time',
      '/library/weekly/aa102505a.htm'));
  Articles.Add(TArticle.Create(
      'Memory Leaks in Delphi Applications',
      '/od/oopindelphi/a/memoryleak.htm'));
end;

Note that while the DataSource property is assigned and the DataBind method is called - at run time - no items will be renderd! Reason? We haven't specified the ItemTemplate!

Take a time to look at the resulting HTML:

<table id="DataList1" cellspacing="0" border="0" 
       style="border-collapse:collapse;">
<tr>
  <td>About Delphi Programming</td>
</tr>
<tr>
  <td></td>
</tr><tr>
  <td></td>
</tr><tr>
  <td></td>
</tr><tr>
        <td>
    <a id="DataList1__ctl4_HyperLink1" 
     href="http://delphi.about.com">delphi.about.com</a>
  </td>
</tr>
</table>

The "About Delphi Programming" string is what we placed in the Header Template. The "<a id="DataList1__ctl4_HyperLink1" href="http://delphi.about.com">delphi.about.com</a>" is the HyperLink control we added to the FooterTemplate.
Finally, there are 3 empty rows each having 2 empty cells! Note that the "Articles" property has 3 items and that each article has two properties. But, the content is not rendered.

Since I've already explained how to create a sample ItemTemplate (declaratively inside the control's markup tags) for the Repeater control and how DataSource and DataBind (and the DataBinder class) are used - this time I'll show you how to create one of the templates programmatically.

Implementing the ITemplate Interface
To create any of the templates programmatically a custom class needs to implement the ITemplate interface. ITemplate has only one procedure, InstantiateIn, which receives a Control parameter. The control passed to InstantiateIn defines the Control object to which child controls in the template will be parented. Here's the full source of a custom class implmenting the ITemplate interface.
TDataListItemTemplate = class(System.Object, ITemplate)
public
  procedure InstantiateIn(container: Control);
  procedure ItemBinding (Sender : TObject; e:EventArgs);
end;
...
procedure TDataListItemTemplate.InstantiateIn(
  container: Control);
var
  ph : PlaceHolder;
  hl : HyperLink;
begin
  ph := PlaceHolder.Create;

  hl := HyperLink.Create;

  ph.Controls.Add(hl);

  Include(ph.DataBinding, ItemBinding);

  container.Controls.Add(ph);
end; (*InstantiateIn*)

procedure TDataListItemTemplate.ItemBinding(
  Sender: TObject; 
  e: EventArgs);
const
  ADPUrl = 'http://delphi.about.com';
var
  ph : PlaceHolder;
  hl : HyperLink;
  container : DataListItem;
begin
  ph := Sender as PlaceHolder;
  container := ph.NamingContainer as DataListItem;

  hl := ph.Controls[0] as HyperLink;

  hl.Text := TArticle(container.DataItem).Title;
  hl.NavigateUrl := ADPUrl+TArticle(container.DataItem).URL;
  
end; (*ItemBinding*)

The InstantiateIn procedure creates and adds controls to the specified container control. If data binding is required on any of these controls, the DataBinding event must be hooked up.

I decided to use the PlaceHolder control as it provides no rendering of its own and can be used as a container. A HyperLink control is created and placed "inside" the PlaceHolder.
As already explained, when a control is binded (DataBind is called for the control) - all the child controls are also binded. A DataBinding handler is needed for each control that would require DataBinder.Eval in the inline template. With this in mind, we only need to handle the DataBinding event of the PlaceHolder - all the child controls can be bound to some value in this single event handler.

DataBinding even handler explained
A custom ItemBinding handles the DataBinding event. The sender parameter is the control on behalf of which you're handling the DataBinding event (PlaceHolder). The NamingContainer property of the sender indicates the nearest control that implements INamingContainer. The nearest container for a child control generated within a DataList's item is the DataListitem object of the corresponding item. Getting this reference is essential, as it is the only way to access the bound data.

Once we lay our hands on the DataItem, by simply casting it to the correct class (TArticle) we can assign values to properties of the HyperLink control created in the InstantiateIn implementation.

Note: while this looks messy, it's quite straight-forward ... just follow the code :)

Finally, the page rendered to the user:

DataList in Browser

Download the full source to explore. Also, try playing with various properties of the DataList.

To the next chapter: A Beginner's Guide to ASP.NET Programming for Delphi developers
That's it for today. In the next chapter we'll continue exploring the topic of data binding in ASP.NET.

If you need any kind of help at this point, please post to the Delphi Programming Forum where all the questions are answered and beginners are treated as experts.

A Beginner's Guide to ASP.NET Programming for Delphi developers: Next Chapter >>
>> Developing and Using Custom User Controls in ASP.NET

©2014 About.com. All rights reserved.