【问题标题】:Group one DataSet with Nested Repeater使用嵌套中继器对一个数据集进行分组
【发布时间】:2019-12-06 13:51:39
【问题描述】:

假设我有一些这样的图书数据:

我有一个类似SELECT * FROM BookData 的查询,它以上述格式输出。

我想使用嵌套转发器控件以 html <table> 的形式输出数据,看起来像这样,数据结果按作者分组:

到目前为止,我的 asp.net 网络表单代码如下所示:

<table>
    <asp:Repeater ID="RepeaterInner" runat="server">
    <ItemTemplate>
    <tr>
        <td><asp:TextBox Text='<%# Eval("Book") %>' /></td>
        <td><asp:TextBox Text='<%# Eval("Author") %>' /></td>
        <td><asp:TextBox Text='<%# Eval("PublishDate") %>' /></td> 
        <td><asp:TextBox Text='<%# Eval("Pages") %>' /></td>         
    </tr>
    </ItemTemplate>
    </asp:Repeater>
</table>

还有我的后台代码:

protected void Page_Load(object sender, EventArgs e)
        {          

            DataSet ds = GetData();
            RepeaterInner.DataSource = ds;
            RepeaterInner.DataBind();

        }

        private DataSet GetData() 
        {
            string CS = ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
            using (SqlConnection con = new SqlConnection(CS))
            {
                using (SqlCommand cmd = new SqlCommand("spGetData"))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Connection = con;
                    con.Open();
                    SqlDataAdapter da = new SqlDataAdapter();
                    da.SelectCommand = cmd;
                    DataSet ds = new DataSet();
                    da.Fill(ds);
                    con.Close();
                    return ds;                   
                }
            }
        }

对于最终产品,我希望它看起来像这样:

<table>
    <asp:Repeater ID="RepeaterOuter" runat="server">
    <ItemTemplate>
        <tr>
        <td><asp:TextBox Text='<%# Eval("Author") %>' /></td>
        </tr>
        <asp:Repeater ID="RepeaterInner" runat="server">
        <ItemTemplate>
        <tr>
            <td><asp:TextBox Text='<%# Eval("Book") %>' /></td>
            <td><asp:TextBox Text='<%# Eval("PublishDate") %>' /></td> 
            <td><asp:TextBox Text='<%# Eval("Pages") %>' /></td>         
        </tr>
        </ItemTemplate>
        </asp:Repeater>    
    </ItemTemplate>
    </asp:Repeater>
</table>

但我真的很困惑如何才能实现上述目标。可以用我的一个存储过程生成的上面的DataSet 来完成吗?如果有的话,我需要为每个中继器的 ItemDataBound 事件处理程序做什么?

谢谢。

【问题讨论】:

    标签: c# asp.net webforms


    【解决方案1】:

    您的存储过程看起来只返回一个数据表。所以 GetData 方法可能应该返回 DataTable 而不是 DataSet

    private DataTable GetData()
    {
        DataTable dt = new DataTable();
        using (SqlConnection c = new SqlConnection(ConfigurationManager.ConnectionStrings["MyDB"].ConnectionString))
        {
            c.Open();
            using (SqlCommand cmd = new SqlCommand("spGetData", c))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                using (SqlDataAdapter da = new SqlDataAdapter(cmd))
                {
                    da.Fill(dt);
                }
            }
        }
        return dt;
    }
    

    Servy 的解决方案帮助我更好地理解IGrouping。更多地基于他的想法: 你的Page_Load 方法:

    protected void Page_Load(object sender, EventArgs e)
    {
        DataTable dataTbl = this.GetData();
    
        //Cast the Rows collection so we can use LINQ
        IEnumerable<dynamic> data = dt.Rows.Cast<DataRow>()
    
            // Group the DataRows by the column ["Author"]
            .GroupBy<DataRow, String>(d => Convert.ToString(d["Author"]))
    
            // GroupBy returns an IEnumerable<IGrouping<TKey, TSource>>
            // in this case we have a String (Authors Name) and 
            // DataRows with the book information. From these IGroupings
            // we want to return a dynamic class that has properties:
            //  - Author (string it is the .Key in the IGrouping) 
            //  - Books (Collection of another dynamic class that has Book properties)
            .Select<IGrouping<String, DataRow>, dynamic>(grp => {
                return new {
                    Author = grp.Key,
                    // grp right now is a collection of DataRows
                    // make each row into a dynamic class that has
                    // book properties so that Eval("PropName")
                    // plays nice
                    Books = grp.Select<DataRow, dynamic>(row => {
                        return new {
                            Book = Convert.ToString(row["Book"]),
                            PublishDate = Convert.ToString(row["PublishDate"]),
                            Pages = Convert.ToString(row["Pages"])
                        };
                    })
                };
            });
    
        RepeaterOuter.DataSource = data;
        RepeaterOuter.DataBind();
    }
    

    页面代码:

    <table>
        <asp:Repeater ID="RepeaterOuter" runat="server">
            <ItemTemplate>
                <tr>
                    <td><asp:TextBox runat="server" Text='<%# Eval("Author") %>' /></td>
                </tr>
                <asp:Repeater ID="RepeaterInner" runat="server" DataSource='<%# Eval("Books") %>'>
                    <ItemTemplate>
                    <tr>
                       <td><asp:TextBox runat="server" Text='<%# Eval("Book") %>' /></td>
                       <td><asp:TextBox runat="server" Text='<%# Eval("PublishDate") %>' /></td> 
                       <td><asp:TextBox runat="server" Text='<%# Eval("Pages") %>' /></td>
                    </tr>
                    </ItemTemplate>
                </asp:Repeater>    
            </ItemTemplate>
        </asp:Repeater>
    </table>
    

    【讨论】:

      【解决方案2】:

      您可以使用GroupBy按作者分组数据,然后您可以简单地将内部中继器绑定到该组书籍:

      RepeaterOuter.DataSource = data.GroupBy(book => book.Author, (Author, Books) => new
      {
          Author,
          Books,   
      });
      

      现在您已经将数据转换为正确的格式,您只需要将书籍收藏绑定到标记中的内部中继器:

      <asp:Repeater ID="RepeaterInner" runat="server" DataSource='<%# Eval("Books") %>'>
      

      【讨论】:

      • data.GroupBy(book =&gt; book.Author, (Author, Books) 中的data 是什么?它在Page_Load 事件中不存在。
      • @MicroR 这是你拥有的数据,你想用来填充你的转发器。
      • 我拥有的数据在DataSet 中,没有DataSet.GroupBy。那么.GroupBy 是什么对象呢?
      • @MicroR 您需要获取表格的行,而不是对整个集合进行操作。
      • 感谢您的帮助,但我只是不明白您的解释。我也在研究这个解决方案,但也没有工作:forums.asp.net/t/…
      【解决方案3】:

      cmd.prompt 解决方案的更简化的 lambda 表达式:

          DataTable data = GetData();
      
          var groupedData = data.AsEnumerable()
              .GroupBy(d => new
              {
                  Author = d["Author"]
              })
              .Select(grp => new
              {
                  grp.Key,
                  Books = grp.Select(row => new
                  {
                      Book = row["ID"],
                      PublishDate = row["Name"],
                      Pages = row["Pages"]
                  })
              });
      
          RepeaterOuter.DataSource = groupedData;
          RepeaterOuter.DataBind();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-18
        • 1970-01-01
        • 2021-10-19
        • 1970-01-01
        • 1970-01-01
        • 2021-02-15
        相关资源
        最近更新 更多