.aspx
files avoiding code-behind files because in my opinion it increases readability and manageability. One of the main drawbacks when using the Repeater in conjunction with databinding syntax is the need for casting the
DataItem
property to it's actual type:I would like to share my take on a strongly typed Repeater which removes the need for casting objects, increases productivity and readability and unlocks intellisense!
The solution
The solution requires you to create two base classes which includes the core functionality and then for every typed Repeater create a simple inherited class which defines the type. As you might have noticed in the above screenshot I introduced a new property called
TypedItem
. You are free to create a name which suits your needs e.g. Container.I
for improved readability.Setting up the base classes:
1. Create a generic Repeater base class
This is the main workhorse of the solution. It was neccessary to override the
InitializeItem
method of the Repeater
class because the default Repeater works with the private variables for the templates. This implementation uses the properties for each template which is required because we will be overriding the ItemTemplate
and AlternatingItemTemplate
for our typed Repeaters.Also the
CreateItem
method is overriden to actually create a generic RepeaterItem<T>
which will be created in step 2.using System.Web.UI; using System.Web.UI.WebControls; public class GenericRepeaterBase<T> : Repeater where T : class { protected override RepeaterItem CreateItem(int itemIndex, ListItemType itemType) { return CreateRepeaterItem(itemIndex, itemType); } private static GenericRepeaterItem<T> CreateRepeaterItem(int itemIndex, ListItemType itemType) { return new GenericRepeaterItem<T>(itemIndex, itemType); } protected override void InitializeItem(RepeaterItem item) { ITemplate template = (ITemplate)null; switch (item.ItemType) { case ListItemType.Header: template = HeaderTemplate; break; case ListItemType.Footer: template = FooterTemplate; break; case ListItemType.Item: template = ItemTemplate; break; case ListItemType.AlternatingItem: template = AlternatingItemTemplate; if (template != null) break; else goto case 2; case ListItemType.Separator: template = SeparatorTemplate; break; } if (template == null) return; template.InstantiateIn((Control)item); } }
2. Create a generic RepeaterItem base class
This class contains the property that you use while working with the Repeater. You can rename the
TypedItem
property as you wish.using System.Web.UI.WebControls; public class GenericRepeaterItem<T> : RepeaterItem where T : class { public GenericRepeaterItem(int itemIndex, ListItemType itemType) : base(itemIndex, itemType) { } public T TypedItem { get { return (T)this.DataItem; } } }
Usage:
3. Create a typed Repeater
Now for every Repeater that you would like to use strongly typed you must create an easy implementation of the
GenericRepeaterBase<T>
class. The example below creates the PersonRepeater
mentioned before.The
PersistenceMode
attribute needs to be redefined because it is not automatically inherited. The TemplateContainer
attribute and the generic type definition on the class make the neccessary definitions for the Repeater to work.public class PersonRepeater : GenericRepeaterBase<GenericRepeaterItem<Person>> { [PersistenceMode(PersistenceMode.InnerProperty)] [TemplateContainer(typeof(GenericRepeaterItem<Person>))] public override ITemplate ItemTemplate { get; set; } [PersistenceMode(PersistenceMode.InnerProperty)] [TemplateContainer(typeof(GenericRepeaterItem<Person>))] public override ITemplate AlternatingItemTemplate { get; set; } }
4. Use it!
public class Person { public string Name { get; set; } public DateTime DateOfBirth { get; set; } }
<%@ Register TagPrefix="asp" Namespace="TypedRepeater" Assembly="TypedRepeater" %> <asp:PersonRepeater runat="server"> <ItemTemplate> Name: <% #Container.TypedItem.Name %><br /> Date of birth: <%#Container.TypedItem.DateOfBirth.ToShortDateString() %> </ItemTemplate> </asp:PersonRepeater>
I hope this code brings you lots of joy! ;)