Creating A Custom DataBound Templated Control In ASP.NET 2.0

Below is the html source view of the custom templated databound control. Note that it is currently referencing an ObjectDataSource control. The SelectMethod property of the ObjectDataSource control calls a method named GetStudents which returns List<Student>

<demo:SimpleTemplatedControl 
   ID="myTemplatedControl"
runat="server" DataSourceID="ObjectDataSource1"> <ItemTemplate> <asp:Label ID="labelTemp" runat="server" Text='<%# Eval("FirstName") %>'> </asp:Label> <hr /> </ItemTemplate> </demo:SimpleTemplatedControl> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetStudents" TypeName="DataTestManager"> </asp:ObjectDataSource>

In the example above, the custom control contains an ItemTemplate, and the Eval expression is used to bind to the FirstName property of the Student object returned from the ObjectDataSource.

The first bit of code needed is to create a container control for the ItemTemplate.  Here is a minimal implementation:

  1     public class SimpleItem : Control, IDataItemContainer
  2     {
  3         public SimpleItem(object dataItem, int index)
  4         {
  5             _DataItem = dataItem;            
  6             _DataItemIndex = _DisplayIndex = index;           
  7         }
  8         
  9         private object _DataItem;
 10         public object DataItem
 11         {
 12             get { return _DataItem; }
 13         }
 14 
 15         private int _DataItemIndex;
 16         public int DataItemIndex
 17         {
 18             get { return 0; }
 19         }
 20 
 21         private int _DisplayIndex;
 22         public int DisplayIndex
 23         {
 24             get { return 0; }
 25         }        
 26     }

Lines 9 through 25 are required members of IDataItemContainer.  Although this class inherits from Control, it does not contain any behavior for rendering.  It will be used in the SimpleTemplatedControl below:

  1     public class SimpleTemplatedControl : CompositeDataBoundControl
  2     {
  3         
  4         private ITemplate _ItemTemplate;
  5         [PersistenceMode(PersistenceMode.InnerProperty),
  6         TemplateContainer(typeof(SimpleItem))]
  7         public ITemplate ItemTemplate
  8         {
  9             get { return _ItemTemplate; }// get
 10             set { _ItemTemplate = value; }// set
 11         }// property        
 12 
 13         protected override int CreateChildControls(
 14             System.Collections.IEnumerable dataSource, 
 15             bool dataBinding)
 16         {
 17             int count = 0;
 18             if (dataBinding)
 19             {
 20                 foreach (object dataItem in dataSource)
 21                 {                    
 22                     if (ItemTemplate!=null)
 23                     {   
 24                         // create instance of SimpleItem control
 25                         SimpleItem item = 
 26                             new SimpleItem(dataItem, count++);
 27 
 28                         // instantiate in new item object
 29                         ItemTemplate.InstantiateIn(item);
 30                         
 31                         // add item to Controls collection
 32                         this.Controls.Add(item);
 33                         
 34                         // need to support <%# %> expressions
 35                         item.DataBind();
 36                     }
 37                     // add a break between each item
 38                     this.Controls.Add(new LiteralControl("<br />"));
 39                 }
 40             }
 41             return count;
 42         }
 43     }

That's it! Some points worthy of noting... Line 5 allows the ItemTemplate to be inner content of the SimpleTemplatedControl. Line 6 specifies that the ItemTemplate's container control is SimpleItem. This allows expressions such as Eval or Bind to be properly scoped for databinding. If line 35 was not there - the Eval expression would be ignored.

10 Comments

  • Very nice. I haven't played around much with the CompositeDataBoundControl class but your example makes it easy to get started with it.

  • Wow! This was exactly what I was looking for, great example.

    Thanks,
    Q

  • Hi Micheal, I spent a little while today designing my own templated control. It works much like the repeater control but I wanted to add a few more features. It was working perfectly, only the syntax binding expressions didn't appear to work. Thanks for your comments and for pointing out that line 35 is very important to ensure this functionality works - it makes perfect sense, but I couldn't see the wood for the trees earlier.

  • Good simple example! I think it is too bad that the example doesn't maintain state upon PostBack. It would be ideal to make people understand state maintenance as well as making this example more useful!

  • How do you create an additional level of templating like the GridView does.

    ..GridView..

    -- How do you get to this point?

  • 1. what else we can do with custom controls? can u tell me?
    2. Creating A Custom DataBound Templated Control In ASP.NET 2.0 is how well efficient than gridview and datagrid control????
    can some one tell me...

  • Great article. Plain and simple and straight to the point. Keep putting out good ones like this one.

  • This is the first example of a databound templated control that's worked for me. I even tried the ones in msdn to no avail. Thanks for the concise code.

  • It is very easy to modify this example to retain state on postback. All you have to do is eliminate line 18, or replace it with a check for dataSource being non-Null. On postback, the dataBinding parameter is false, but dataSource will be a DummyDataSource, provided by base class, to allow the controls to recreate and re-load their data from ViewState.
    On a side note, the SimpleItem should also implement INamingContainer (contains no members, just a marker interface). This is important if you raise an event for each item's bind, to allow developers to manipulate template instanced in code. INamingContainer is needed to allow FindControl to work.

  • Hi Claudio,
    IDataItemContainer already inherits INamingContainer.

    In this sample, the templated control inherits CompositeDataBoundControl and I think that's why its DataSource is automatically serialized to ViewState without any extra code.

Comments have been disabled for this content.