【问题标题】:How can I access the group of a linq group-by query from a nested repeater control?如何从嵌套转发器控件访问 linq group-by 查询的组?
【发布时间】:2010-03-26 21:09:39
【问题描述】:

我正在使用 linq group by 查询(带有两个分组参数),并希望在嵌套转发器中使用结果数据。

var dateGroups = from row in data.AsEnumerable()
    group row by new { StartDate = row["StartDate"], EndDate = row["EndDate"] };

“data”是来自 SqlDataAdapter 填充的 DataSet 的 DataTable。 "dateGroups" 用于父中继器,我可以使用 Eval("key.StartDate") 和 Eval("key.EndDate") 访问组键。

由于 dateGroups 实际上包含按开始/结束日期整齐分组的所有数据行,我想访问这些行以在子转发器中显示数据。

我会将子中继器的数据源设置为什么?我已经尝试了我能想到的标记中的每一种表达方式;我认为问题在于我正在尝试访问一个匿名成员(我不知道如何访问。)如果结果不是很明显,那么在每次迭代中访问元素的表达式是什么子中继器?

是否有一个表达式可以让我在标记中设置 DataSource,还是必须在父中继器中某个事件的代码隐藏中?

【问题讨论】:

    标签: asp.net linq repeater anonymous-types


    【解决方案1】:

    我最终搜索了一下,找到了this。使用它我创建了一个字典,其键是 StartDate/EndDate 组合,值是 DataRows 的列表:

    var dateGroups = (from row in data.AsEnumerable()
        group row by new
        {
            StartDate = row["StartDate"],
            EndDate = row["EndDate"]
        } into g select g)
        .ToDictionary(gdc => gdc.Key, gdc => gdc.ToList());
    

    父Repeater以编程方式绑定,现在我有一个内部GridView绑定到DataRows列表:

    <asp:Repeater ID="CourseScheduleRepeater" runat="server">
        <ItemTemplate>
            <h4><%# Eval("key.StartDate", "{0:MMM. dd, yyyy}") %> - <%# Eval("key.EndDate", "{0:MMM. dd, yyyy}") %></h4>
    
            <asp:GridView ID="GridView1" runat="server"
                    DataSource='<%# Eval("value") %>'>
                <Columns>
                    <asp:TemplateField HeaderText="Section">
                        <ItemTemplate>
                            <%# DataBinder.Eval(Container.DataItem, "[SectionCode]") %>
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Location">
                        <ItemTemplate>
                            <%# DataBinder.Eval(Container.DataItem, "[LocationName]") %>
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField HeaderText="Schedule">
                        <ItemTemplate>
                            <%# DataBinder.Eval(Container.DataItem, "[Schedule]") %>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>        
            </asp:GridView>
    
        </ItemTemplate>
    </asp:Repeater>
    

    我唯一的抱怨是我必须使用模板字段,并且 GridView 中显示了两个额外的列 - “RowError”和“HasErrors”。有人知道为什么会出现这些专栏吗?

    【讨论】:

    • 使用ToDictionary 是一种很好的方法,尽管您不需要使用它。相反,您可以使用 GroupBy 的重载来塑造组结果。
    【解决方案2】:

    我发现这个帖子很有帮助。这是我使用外部中继器和内部中继器的概念验证解决方案。

    如何使用 LINQ 分组来填充嵌套数据绑定控件

    <form id="form1" runat="server">
    <div>
        <table>
            <asp:Repeater ID="Repeater1" runat="server">
                <ItemTemplate>
                    <tr>
                        <td>
                            <%# Eval("key.FavoriteColor")%>
                        </td>
                        <td>
                            <%# Eval("key.FavoriteFood")%>  
                        </td>
                        <td colspan="2"></td>
                    </tr>
                    <asp:Repeater ID="Repeater2" DataSource='<%# Eval("value") %>' runat="server">
                        <ItemTemplate>                      
                            <tr>
                                <td>
                                    <%# Eval("ID") %>
                                </td>
                                <td>
                                    <%# Eval("Name") %>
                                </td>
                                <td>
                                    <%# Eval("FavoriteColor") %>
                                </td>
                                <td>
                                    <%# Eval("FavoriteFood") %>
                                </td>
                            </tr>                       
                        </ItemTemplate>
                    </asp:Repeater>
                </ItemTemplate>
            </asp:Repeater>
        </table>
    </div>
    </form>
    
    
    
    
    public partial class WebForm1 : Page
    {
        private List<Child> CreateChildren()
        {
            List<Child> children = new List<Child>();
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Green,
                FavoriteFood = Child.Food.IceCream,
                Name = "Sam",
                ID = 1,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Blue,
                FavoriteFood = Child.Food.Hamburgers,
                Name = "Tom",
                ID = 2,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Blue,
                FavoriteFood = Child.Food.Pizza,
                Name = "Fred",
                ID = 3,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Orange,
                FavoriteFood = Child.Food.Tacos,
                Name = "Mark",
                ID = 4,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Green,
                FavoriteFood = Child.Food.Pizza,
                Name = "Harry",
                ID = 5,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Pink,
                FavoriteFood = Child.Food.Pizza,
                Name = "Natalie",
                ID = 6,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Green,
                FavoriteFood = Child.Food.Pizza,
                Name = "Amy",
                ID = 7,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Yellow,
                FavoriteFood = Child.Food.Hamburgers,
                Name = "Katie",
                ID = 8,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Red,
                FavoriteFood = Child.Food.IceCream,
                Name = "Betty",
                ID = 9,
            });
    
            children.Add(new Child
            {
                FavoriteColor = Child.Color.Pink,
                FavoriteFood = Child.Food.Pizza,
                Name = "Erica",
                ID = 10,
            });
    
            return children;
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
            List<Child> children = CreateChildren();
    
            // Use LINQ to create the groupings.
            var query = (from c in children
                         group c by new
                         {
                            c.FavoriteColor,
                            c.FavoriteFood,
                         }
                         into g select g).ToDictionary(g => g.Key, g => g.ToList());
    
            // Here is the same code using LINQ chain methods.
            // var query = children.GroupBy(c => new { c.FavoriteColor, c.FavoriteFood }).Select(g => g).ToDictionary(g => g.Key, g => g.ToList());
    
            Repeater1.DataSource = query;
            Repeater1.DataBind();
        }
    }
    
    public class Child
    {
        public enum Color
        {
            Black,
            Blue,
            Brown,
            Green,
            Orange,
            Pink,
            Purple,
            Red,
            Yellow,
            White,
        }
    
        public enum Food
        {
            Chicken,
            Hamburgers,
            IceCream,
            Pizza,
            Tacos,
        }
    
        public int ID { get; set; }
        public string Name { get; set; }
        public Color FavoriteColor { get; set; }
        public Food FavoriteFood { get; set; }
    }
    

    【讨论】:

      【解决方案3】:

      使用已知类类型而不是匿名类。否则你将不得不使用反射来检查变得丑陋的匿名类型。

      【讨论】:

      • 在弄清楚如何使用 ToDictionary 表达式访问匿名成员后,我意识到我仍然无法访问内部网格视图所需的其他成员。我为键创建了一个包含两个成员的类,然后在每次重复器迭代中过滤了内部网格视图的原始 DataTable。
      • 可以使用匿名类。我们不需要使用反射。
      【解决方案4】:

      我认为问题在于我正在尝试访问匿名成员(我不知道如何访问。)

      你能用你自己的类替换匿名类型吗?

      【讨论】:

        【解决方案5】:

        以下可以很好地将GroupBy 绑定到嵌套的Repeater。关键是拨打CopyToDataTable。以下是关于其他答案的一些说明:

        1. 我们可以使用匿名类型来代替已知的类类型。
        2. 我们可以使用GroupBy 的结果而不调用ToDictionary

        代码隐藏

        使用GroupBy overload that lets us specify the type of both the key and the group。在这种情况下,密钥是具有FirstNameLastName 属性的匿名类,结果是我们从IEnumerable&lt;DataRow&gt; 复制的DataTable。我们要做那个复制,因为Repeaters 不能很好地绑定到IEnumerable&lt;DataRow&gt;

        var grouped = dataRows
            .GroupBy(row => new
            {
                FirstName = row["FirstName"],
                LastName = row["LastName "]
            },
            (key, group) => new
            {
                Key = key,
                Group = group.CopyToDataTable()
            });
        
        rptOuter.DataSource = grouped;
        rptOuter.DataBind();
        

        标记

        我们将外部中继器中的Eval 发送到Key,将内部中继器发送到GroupPhoneNumber 只是原始 DataTable 中的列名称之一。

        <asp:Repeater ID="rptOuter" runat="server">
            <ItemTemplate>
                <p><%# Eval("Key.FirstName") %></p>
                <p><%# Eval("Key.LastName") %></p>
                <asp:Repeater ID="rptInner" runat="server"
                    DataSource='<%# Eval("Group") %>' >
                    <ItemTemplate>
                        <p><%# Eval("PhoneNumber") %></p>
                    </ItemTemplate>
                </asp:Repeater>
            </ItemTemplate>
        </asp:Repeater>
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-09-30
          • 2014-05-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-06
          • 2021-02-26
          相关资源
          最近更新 更多