Вложенные повторители в ASP.NET - PullRequest
40 голосов
/ 26 августа 2010

У меня есть класс, который содержит иерархические данные. Я хочу представить эти данные в моем веб-приложении ASP.net, используя вложенные повторители. Как мне это сделать? Я когда-либо делал только один уровень вложенности, как мне сказать пять уровней?

Каждый элемент может иметь ноль или несколько подпунктов. Я в основном просто делаю отступы на каждом подуровне, используя некоторые вещи CSS. Я не хочу использовать элемент управления treeview, я хочу строго придерживаться повторителя.

Обновление:
Мои данные поступают из базы данных. У меня есть элемент данных с некоторыми базовыми свойствами.

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

Тогда у меня есть таблица «многие ко многим» с:

Parent
{
   ParentID,
   ChildID
}

Я перебираю каждый элемент и показываю его дочерние элементы; и его детские дети. Я предполагаю, что это лучше всего сделать с помощью вложенных повторителей, но я могу ошибаться.

Ответы [ 4 ]

80 голосов
/ 26 августа 2010

Я обнаружил, что самый простой способ сделать вложенные повторители, не беспокоясь о событиях привязки данных, это просто установить 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;
}
34 голосов
/ 26 августа 2010

Работать с источником данных всегда чище, чем возиться с 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
11 голосов
/ 26 августа 2010

Вы можете вложить репитеры без проблем.Глубина более 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
    }
2 голосов
/ 26 августа 2010
<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 не является рекурсивным, он получит только детей.

...