Nested Repeaters in ASP.NET

拜拜、爱过 提交于 2019-11-27 07:33:27
Jon Hanna

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

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;
}

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
    }
<asp:Repeater ID="R1" runat="server">
    <ItemTemplate>
        <asp:Repeater ID="R2" runat="server">
        </asp:Repeater>
    </ItemTemplate>
</asp:Repeater>


R1.ItemDataBound += (s, e) =>
{
    var r2 = e.Item.FindControl("R2") as Repeater;
    r2.DataSource = something;
    r2.DataBind();
};

Be aware that FindControl is not recursive, it will only get the children.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!