【问题标题】:Displaying an IGrouping<> with nested ListViews显示带有嵌套 ListViews 的 IGrouping<>
【发布时间】:2010-09-15 10:26:11
【问题描述】:

我需要从我的数据访问层检索一组按 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&lt;IGrouping&lt;Manufacturer, Widget&gt;&gt; 传递给 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>

注意 WidgetsListView 的 DataSource 属性本身是如何被数据绑定的。如何在不重塑数据的情况下复制此功能?

这有点复杂,抱歉,如果我应该提出一个单独的问题。

【问题讨论】:

    标签: asp.net linq listview


    【解决方案1】:

    好的,我要反驳我之前的陈述。由于 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>
    

    【讨论】:

      【解决方案2】:

      我在这方面花了很长时间。终于找到了解决办法,就是这么简单。


      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,但您只需将其转换为正确的类型即可。

      希望这对其他人有所帮助。

      【讨论】:

      • 在您的项目模板中,您可以将&lt;%#((DataRow)Container.DataItem)["ChildDataColumn1"] %&gt; 替换为&lt;%# Eval("ChildDataColumn1") %&gt;
      • 很棒的发现!我正在寻找某种价值,例如“.Values”之类的。它也很难放入搜索查询中。谢谢!
      【解决方案3】:

      当你使用 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);
      

      这会让你从方法中返回结果。

      【讨论】:

      • 感谢您的建议。我用更多信息更新了我原来的问题。
      猜你喜欢
      • 1970-01-01
      • 2016-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-16
      • 1970-01-01
      • 2021-09-22
      • 2014-10-31
      相关资源
      最近更新 更多