Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Displaying an IGrouping<> with nested ListViews

I need to retrieve a set of Widgets from my data access layer, grouped by widget.Manufacturer, to display in a set of nested ASP.NET ListViews.

The problem is that (as far as I can tell) the nested ListView approach requires me to shape the data before using it, and I can't figure out the best approach to take. The best I've been able to come up with so far is to put a LINQ query in my data access layer like so:

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

Of course, anonymous types can't be passed around, so that doesn't work. Defining a custom class to enclose data seems like the wrong way to go. Is there some way I can perform the grouping on the ASP.NET side of things? I'm using ObjectDataSources to access the DAL.

Updated: OK, I'm not creating an anonymous type anymore, and instead my DAL passes an IEnumerable<IGrouping<Manufacturer, Widget>> to the ASP.NET page, but how can I use this in my ListViews? I need to render the following HTML (or something pretty much like it)

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

Originally, I had a ListView within a ListView like so:

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

Note how the DataSource property of WidgetsListView is itself databound. How can I duplicate this functionality without reshaping the data?

This is getting kind of complicated, sorry if I should have just made a separate question instead.

like image 246
Brant Bobby Avatar asked Oct 06 '08 00:10

Brant Bobby


1 Answers

Ok, I'm going to contradict my prior statement. Since eval wants some kind of property name in the nested control, we should probably shape that data.

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

// and use it thusly...

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

/// and even later...

<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>
like image 189
Amy B Avatar answered Oct 13 '22 23:10

Amy B