【问题标题】:Nested Repeaters in ASP.NETASP.NET 中的嵌套中继器
【发布时间】:2010-08-26 00:55:30
【问题描述】:

我有一个包含分层数据的类。我想使用嵌套转发器在我的 ASP.net webapp 中呈现这些数据。我该怎么做呢?我只做过一层嵌套,怎么说是五层呢?

每个项目可以有零个或多个子项目。我基本上只是使用一些 css 东西在每个 subleveling 处缩进。我不想使用 treeview 控件,我想严格坚持使用中继器。

更新:
我的数据来自数据库。我有一个包含一些基本属性的项目数据表。

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

然后我有一个多对多表:

Parent
{
   ParentID,
   ChildID
}

我正在遍历每个项目并显示其子项;及其孩子的孩子。我认为这最好通过嵌套中继器来完成,但我可能错了。

【问题讨论】:

  • 您显示的是什么类型的数据?表格数据?清单?数据来自哪里? (如果您从数据库中获取,您最终可能会遇到许多选择的问题,因为您将获得每个中继器的数据绑定)
  • 发送您的中继器将显示的示例数据。
  • 不理解所做的编辑。虽然我想不出 4.0 中会影响到这一点的任何具体内容,但 (A) 我可能是错的,(B) 提问者是如何知道的,如果他们知道,他们就不会问这个问题。
  • 数据基本上是文本,它来自数据库。我只包括我正在使用的东西的版本,以便可以针对我的环境提出解决方案。
  • @Jon:有什么不懂的最好问,免得一无所知。我从标题中删除的信息已经在标签中。它在标题中是多余的。此外,C# 与这个问题完全无关。如果 Mike 使用的是 VB.NET,答案将是相同的,除了一点语法。最后,“嗨”、“谢谢”、签名和标语都是噪音,不属于问答网站。也许在讨论论坛中,但事实并非如此。

标签: c# asp.net repeater nested-repeater


【解决方案1】:

我发现在不担心数据绑定事件的情况下执行嵌套中继器的最简单方法是使用 <%# %> 语法设置 DataSource。

例如:

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

这是假设您的 Departments 类有一个 Employees 属性 - 例如:

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

如果您的外部中继器对象没有与内部中继器对象对应的属性,您仍然可以使用此技巧,方法是在您的代码隐藏中添加一个执行计算的方法。所以你的内部中继器可能会变成:

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

然后 GetEmployees 可能看起来像:

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

【讨论】:

  • 请通过显示数据的样子来填写这个例子。特别是,“Employees”属性中有什么?
  • @John 这显然是某种具有 Name 属性的对象的枚举。
  • @Jon:呵呵。真的吗?这对我来说很清楚,但对于阅读此答案的下一千人来说可能不是。
  • 完成。我还添加了关于如何处理 Department 没有Employees 属性的情况的注释。
  • 很好的答案。我一直在寻找像这样干净简单的东西!
【解决方案2】:

处理数据源总是比处理 ItemDataBound 更干净,但嵌套中继器时更是如此:

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

内部数据源也可以是评估属性,或对返回所需枚举的方法的调用。请注意,它将使用对象调用。我更喜欢写具体的版本,然后重载:

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

需要注意的一点是,如果您想在父中继器中获取当前对象,则必须通过以下方式获取它:

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

【讨论】:

  • 这是一个偏好问题。我不喜欢在 aspx 中嵌入绑定逻辑,然后仍然不得不求助于代码隐藏来解决任何复杂问题。
  • protected IEnumerable GetNames(object famObj) 函数参数名有什么特别的吗?
  • @Yiping 不,出于某种原因,获取一个家庭中一群人的全名是我想到使用的示例,尽管我不知道为什么。也许这与我当时正在做的事情有关,或者当时在另一个问题中出现。
【解决方案3】:

您可以毫无问题地嵌套中继器。超过 2 层的深度会变得很糟糕。方法如下:

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>

代码隐藏如下:

    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
    }

【讨论】:

  • 它变得很糟糕,但是你使用不必要的 itemdatabound 处理程序而不是仅仅使用数据源让它变得更糟糕。
  • @Jon:在下面回复了您的评论;对于更复杂的绑定逻辑,我发现我的方法更具可扩展性且不那么难看;例如,除了父上下文之外,还需要针对当前安全上下文的过滤器。
  • 是的,当您必须为每个项目的数据绑定提供逻辑时,itemdatabound 就有其价值。但是,当您只是浏览嵌套对象时,我看不到额外的复杂性在这么多不同的地方分裂并迫使人们切换思维模式(使用 aspx 的方式,人们可以继续思考“这是一堆我正在经历的事情”而不是考虑控件何时收到他们的数据绑定调用)收益。
  • 在有时需要代码隐藏模式的庞大代码库中,我发现即使在微不足道的情况下使用相同的模式也很有帮助。找到数据绑定逻辑很容易,并且可以在不花费时间更改模式的情况下对其进行扩展。
【解决方案4】:
<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();
};

注意FindControl 不是递归的,它只会得到孩子。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    • 2011-09-04
    相关资源
    最近更新 更多