简体   繁体   English

ASP.NET中的嵌套中继器

[英]Nested Repeaters in ASP.NET

I have a class that contains hierarchical data. 我有一个包含分层数据的类。 I want to present this data in my ASP.net webapp using nested repeaters. 我想使用嵌套转发器在我的ASP.net webapp中显示这些数据。 How do I do this? 我该怎么做呢? I've only ever done one level of nesting, how do I do say five levels? 我只做了一个级别的嵌套,我怎么说五个级别?

Each item can have zero or many sub items. 每个项目可以有零个或多个子项目。 I'm basically just indenting at each subleveling using some css stuff. 我基本上只是在使用一些CSS的东西缩进每个分段。 I do not want to use the treeview control, I want to strictly stick with a repeater. 我不想使用treeview控件,我想严格坚持使用转发器。

Update: 更新:
My data comes from a database. 我的数据来自数据库。 I have an item datatable with some basic properties. 我有一个带有一些基本属性的数据表。

Item
{
   ID,
   Name,
   Description,
   ...
}

Then I have a many to many table with: 然后我有一个多对多的表:

Parent
{
   ParentID,
   ChildID
}

I'm iterating through each item and displaying its children; 我正在遍历每个项目并展示它的孩子; and its children's children. 和它的孩子的孩子。 I assume this would best be accomplished with nested repeaters, but I could be wrong. 我认为这最好用嵌套的中继器完成,但我可能是错的。

I've found that the simplest way to do nested repeaters without worrying about databinding events is to just set the DataSource using <%# %> syntax. 我发现在不担心数据绑定事件的情况下进行嵌套转发器的最简单方法是使用<%# %>语法设置DataSource。

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: 这假设你的Departments类有一个Employees属性 - 例如:

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: 然后GetEmployees可能看起来像:

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: 处理数据源总是比使用ItemDataBound搞乱更简洁,但在嵌套Repeater时更是如此:

<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. 内部数据源也可以是一个evaluate属性,或者是一个返回所需枚举的方法的调用。 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. 然而,超过2级深度变得令人讨厌。 Here's how: 这是如何做:

The html looks something like this: html看起来像这样:

<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. 请注意FindControl不是递归的,它只会让孩子们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM