Отображение IGrouping <> с вложенными ListViews - PullRequest
10 голосов
/ 06 октября 2008

Мне нужно получить набор виджетов из слоя доступа к данным, сгруппированных по widget.Manufacturer, для отображения в наборе вложенных списков ASP.NET ListViews.

Проблема в том, что (насколько я могу судить) вложенный подход ListView требует от меня формирования данных перед их использованием, и я не могу найти лучший подход для этого. Лучшее, что я смог придумать, - это поместить запрос LINQ в слой доступа к данным, например:

var result = from widget in GetAllWidgets(int widgetTypeID)
             group widget by widget.Manufacturer into groupedWidgets
             let widgets = from widgetGroup in groupedWidgets
                           select widgetGroup
             select new { Manufacturer = groupedWidgets.Key, Widgets = widgets };

Конечно, анонимные типы нельзя передавать, так что это не работает. Определение пользовательского класса для включения данных кажется неправильным путем. Есть ли способ, которым я могу выполнить группировку на стороне ASP.NET вещей? Я использую ObjectDataSources для доступа к DAL.

Обновлено : ОК, я больше не создаю анонимный тип, и вместо этого мой DAL передает IEnumerable<IGrouping<Manufacturer, Widget>> странице ASP.NET, но как я могу использовать это в моих ListViews? Мне нужно сделать следующий HTML (или что-то вроде этого)

<ul>
  <li>Foo Corp.
    <ol>
      <li>Baz</li>
      <li>Quux</li>
    </ol>
  </li>
  <li>Bar Corp.
    <ol>
      <li>Thinger</li>
      <li>Whatsit</li>
    </ol>
  </li>
</ul>

Первоначально у меня был ListView внутри ListView, например, так:

<asp:ListView ID="ManufacturerListView">
    <LayoutTemplate>
        <ul>
            <asp:Placeholder ID="itemPlaceholder" runat="server" />
        </ul>
    </LayoutTemplate>
    <ItemTemplate>
        <li><asp:Label Text='<%# Eval("Manufacturer.Name") %>' />
        <li>
        <asp:ListView ID="WidgetsListView" runat="server" DataSource='<%# Eval("Widgets") %>'>
            <LayoutTemplate>
                <ol>
                    <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
            </ol>
           </LayoutTemplate>
           <ItemTemplate>
               <li><asp:Label Text='<%# Eval("Name") %>'></li>
           </ItemTemplate>
        </asp:ListView>
        </li>
    </ItemTemplate>
</asp:ListView>

Обратите внимание, что свойство DataSource объекта WidgetsListView само по себе связано с данными. Как я могу продублировать эту функцию без изменения данных?

Это становится немного сложнее, извините, если бы я просто вместо этого задал отдельный вопрос.

Ответы [ 3 ]

12 голосов
/ 07 октября 2008

Хорошо, я собираюсь противоречить моему предыдущему утверждению. Поскольку eval хочет какое-то имя свойства во вложенном элементе управления, мы, вероятно, должны сформировать эти данные.

public class CustomGroup<TKey, TValue>
{
  public TKey Key {get;set;}
  public IEnumerable<TValue> Values {get;set;}
}

// и использовать его таким образом ...

IEnumerable<CustomGroup<Manufacturer, Widget>> result =
  GetAllWidgets(widgetTypeId)
  .GroupBy(w => w.Manufacturer)
  .Select(g => new CustomGroup<Manufacturer, Widget>(){Key = g.Key, Values = g};

/// и даже позже ...

<asp:ListView ID="ManufacturerListView">
<LayoutTemplate>
    <ul>
        <asp:Placeholder ID="itemPlaceholder" runat="server" />
    </ul>
</LayoutTemplate>
<ItemTemplate>
    <li><asp:Label Text='<%# Eval("Key.Name") %>' />
    <li>
    <asp:ListView ID="WidgetsListView" runat="server" DataSource='<%# Eval("Values") %>'>
        <LayoutTemplate>
            <ol>
                <asp:PlaceHolder runat="server" ID="itemPlaceholder" />
            </ol>
       </LayoutTemplate>
       <ItemTemplate>
           <li><asp:Label Text='<%# Eval("Name") %>'></li>
       </ItemTemplate>
    </asp:ListView>
    </li>
</ItemTemplate>
</asp:ListView>
5 голосов
/ 20 августа 2009

Я просто потратил немало времени на это. В конце концов нашли решение, и это так просто.


var enumerableData = myData.Tables[0].AsEnumerable();
var groupedData = enumerableData.GroupBy(x => x["GroupingColumn"]);

myParentRepeater.DataSource = groupedData;
myParentRepeater.DataBind();

<asp:Repeater ID="myParentRepeater" runat="server">
  <ItemTemplate>
    <h3><%#Eval("Key") %></h3>
    <asp:Repeater ID="myChildRepeater" runat="server" DataSource='<%# Container.DataItem %>'>
      <ItemTemplate>
        <%#((DataRow)Container.DataItem)["ChildDataColumn1"] %>
        <%#((DataRow)Container.DataItem)["ChildDataColumn2"] %>
      </ItemTemplate>
      <SeparatorTemplate>
        <br />
      </SeparatorTemplate>
    </asp:Repeater>
  </ItemTemplate>
</asp:Repeater>

Eval («Ключ») возвращает сгруппированное значение. При получении дочерней информации Container.DataItem имеет тип IGrouping, но вы просто приводите его к правильному типу.

Надеюсь, это поможет кому-то еще.

3 голосов
/ 06 октября 2008

Когда вы используете Linq для группировки, вы можете получить строго типизированный объект без этой формы:

List<int> myInts = new List<int>() { 1, 2, 3, 4, 5 };
IEnumerable<IGrouping<int, int>> myGroups = myInts.GroupBy(i => i % 2);
foreach (IGrouping<int, int> g in myGroups)
{
  Console.WriteLine(g.Key);
  foreach (int i in g)
  {
    Console.WriteLine("  {0}", i);
  }
}
Console.ReadLine();

В вашем случае у вас будет:

  IEnumerable<IGrouping<Manufacturer, Widget>> result =
    GetAllWidgets(widgetTypeId).GroupBy(w => w.Manufacturer);

Это позволит вам вернуть результат из метода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...