Nested Repeaters in ASP.NET Nested Repeaters in ASP.NET asp.net asp.net

Nested Repeaters in ASP.NET


I've found that the simplest way to do nested repeaters without worrying about databinding events is to just set the DataSource using <%# %> syntax.

For example:

<asp:Repeater runat="server" id="Departments">  <ItemTemplate>    Name: <%# Eval("DeptName") %>    Employees:    <asp:Repeater runat="server" DataSource='<%# Eval("Employees") %>'>      <ItemTemplate><%# Eval("Name") %></ItemTemplate>      <SeparatorTemplate>,</SeparatorTemplate>    </asp:Repeater>  </ItemTemplate></asp:Repeater>

This is presuming that your Departments class has an Employees property - eg:

public class Department {  public string DeptName {get; set;}  public IEnumerable<Employee> Employees {get; set;}}public class Employee {  public string Name {get; set;}}

If your outer-repeater object doesn't have a property corresponding to the inner-repeater object you can still use this trick, by adding a method in your code-behind that does the calculation. So your inner repeater might become:

<asp:Repeater runat="server" DataSource='<%# GetEmployees(Container.DataItem) %>'>

and then GetEmployees might look something like:

protected IEnumerable<Employee> GetEmployees(object item) {  var dept = (Department) item;  // then do whatever is necessary to get the employees from dept  return employees;}


It's always cleaner to deal with the datasource than messing about with ItemDataBound, but this is even more the case when nesting Repeaters:

<asp:Repeater DataSource="<%#ColOfCol%>" runat="server">  <ItemTemplate>    <tr>      <asp:Repeater DataSource="<%#Container.DataItem%>" runat="server">        <ItemTemplate>          <td><%#SomeExtractingMethodLikeEval()%></td>        </ItemTemplate>      </asp:Repeater>    </tr>  </ItemTemplate></asp:Repeater>

The inner datasource could also be an evaluated property, or a call to a method that returns the enumeration wanted. Just be aware that it will be called with an object. I prefer to write the specific version, and then overload:

protected IEnumerable<string> GetNames(Family fam){  foreach(Person p in fam.Members)    yield return p.FirstName + " " + p.Surname;}protected IEnumerable<string> GetNames(object famObj){    return GetNames((Family)famObj);}

One thing to be aware of is that if you want to get the current object in the parent repeater than you have to obtain it with:

((RepeaterItem)Container.Parent.Parent).DataItem


You can nest repeaters without a problem. More then 2 levels deep gets nasty though. Here's how:

The html looks something like this:

<asp:Repeater ID="r1" runat="server" OnItemDataBound="r1_ItemDataBound"><ItemTemplate><!-- top level repeater element template here -->    <asp:Repeater ID="r2" runat="server" onitemdatabound="r2_ItemDataBound">    <ItemTemplate><!-- child repeater element template here -->    </ItemTemplate>    </asp:Repeater></ItemTemplate></asp:Repeater>

The codebehind looks like this:

    protected void r1_ItemDataBound(object sender, RepeaterItemEventArgs e) {        Repeater r2 = (Repeater)e.Item.FindControl("r2");        r2.DataSource = yourDataSourceHere; // you'll have to query for appropriate data        r2.DataBind();    }    protected void r2_ItemDataBound(object sender, RepeaterItemEventArgs e) {        // do the same thing here for the 3rd nested repeater if you have a third, and so on    }