Мне нужно получить набор виджетов с моего уровня доступа к данным, сгруппированных по 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 само является привязкой к данным. Как я могу продублировать эту функцию без изменения данных?
Это становится довольно сложным, извините, если бы я просто задал отдельный вопрос.





Когда вы используете 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);
Это позволит вам вернуть результат метода.
Хорошо, я собираюсь опровергнуть свое предыдущее заявление. Поскольку 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>
Я только что потратил на это довольно много времени. В конце концов нашли решение, и это так просто.
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 («Key») возвращает сгруппированное значение. При получении дочерней информации Container.DataItem имеет тип IGrouping, но вы просто приводите его к правильному типу.
Надеюсь, это поможет кому-то другому.
В шаблоне элемента вы можете заменить <%#((DataRow)Container.DataItem)["ChildDataColumn1"] %> на <%# Eval("ChildDataColumn1") %>.
Отличная находка! Я искал какую-то ценность вроде ".Values" или что-то в этом роде. Его тоже сложно ввести в поисковый запрос. Спасибо!
Спасибо за совет. Я обновил свой исходный вопрос, добавив дополнительную информацию.