65.9K
CodeProject 正在变化。 阅读更多。
Home

嵌套和分组的 Repeater

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (4投票s)

2005 年 8 月 15 日

2分钟阅读

viewsIcon

83643

downloadIcon

974

创建一个使用嵌套ASP.NET中继器的数据驱动报表网页。

引言

使用嵌套的ASP.NET中继器,您可以轻松创建专业的报表样式网页,其中包含标准的ASP.NET控件。CodeProject上的其他文章展示了如何使用用户控件来实现这一点。此示例仅使用标准的Repeater控件,特别是ItemDataBound方法来创建复杂的界面。

背景

我需要创建一个报表,但用户需要能够通过相同的界面更新它,因此SQL Reporting Services和Crystal Reports不适用。我不得不进行大量的研究才能解决一些问题;例如数据绑定语法、查找嵌套控件的技术,所以我决定分享我的成果。感谢在优秀的MSDN论坛上发布答案的人们。

安装

如果您想运行示例,请执行以下步骤

  1. 需要修改连接字符串以连接到您的数据库实例。
  2. 我包含了一个SQL脚本,该脚本创建报表存储过程。这需要针对Northwind数据库运行。

Data

存储过程从Northwind数据库返回两个结果集。

  1. 产品类别
  2. 产品和总销售额

DataSet以标准方式填充。

代码

<asp:Repeater id="rptProducts" runat="server" 
    OnItemDataBound="rptProducts_ItemDataBound">

对于子中继器,您需要在ASPX文件中指定要调用的OnItemDataBound方法。如果您只是以常规方式连接事件,则不会调用它。

1:  protected void rptProducts_ItemDataBound(object sender, 
            System.Web.UI.WebControls.RepeaterItemEventArgs e)
2:  {
3:    if(e.Item.ItemType == ListItemType.Item || 
        e.Item.ItemType == ListItemType.AlternatingItem)
4:    { 
5:      string product =  
          ((DataRowView)e.Item.DataItem).Row.ItemArray[2].ToString(); 
6:      ImageButton i =  
          (ImageButton)e.Item.Controls[0].FindControl("imgDelete"); 
7:      i.CommandName = "Delete"; 
8:      i.CommandArgument = product; 
9:      string script = string.Format(
              "javascript:alert('Delete Product: {0}');", product); 
10:     i.Attributes.Add("onclick", script); 
11:   }
12: }

调用rptProducts_ItemDataBound方法时,我们可以通过将RepeaterItem转换为DataRowView来定位产品数据。[5]在这里,我们检索产品名称,并将其用于传递到ImageButtonCommandArgument中[6-8]。此CommandArgument可以在ImageButton_Command事件中提取,然后用于删除或修改数据库中相关的产品。此方法[1]必须protected,而不是private,否则将无法访问。

1:  private void rptCategories_ItemDataBound(object sender, 
            System.Web.UI.WebControls.RepeaterItemEventArgs e)
2:  {
3:    if(e.Item.ItemType == ListItemType.Item || 
            e.Item.ItemType == ListItemType.AlternatingItem)
4:    {
5:       // find category in RepeaterItem
6:       string category = 
           ((DataRowView)e.Item.DataItem).Row.ItemArray[0].ToString();
7:       Repeater rep = (Repeater)e.Item.FindControl("rptProducts") ;
8:       // pass in category to construct "where clause", 
         // then set DataView as DataSource 
9:       DataView dv = getChildRows(category) ; 
10:      rep.DataSource = dv ; 
11:      rep.DataBind() ; 
12:      // calculate total for product category 
13:      SalesTotal = this.calculateSalesTotals(category) ; 
14:      // Find item in group "footer" and populate label with total 
15:      Repeater r = (Repeater)e.Item.Parent ; 
16:      Label lblSalesTotals = 
                 (Label)r.Controls[e.Item.ItemIndex+ 1].FindControl(
                                                     "lblSalesTotals"); 
17:      lblSalesTotals.Text =  SalesTotal.ToString("C") ; 
18:   }
19: }

父中继器的ItemDataBound方法负责过滤category数据。这是页面上执行嵌套的关键代码。FindControl可以返回对子Repeater的引用[7]。然后可以将DataView控件作为DataSource传递给子Repeater[9-11]。最后,我们计算类别的销售总额,用于组页脚[15-17]。

1: private DataView getChildRows(string Filter)
2: {
3:   string whereClause = 
         string.Format("CategoryName = '{0}'", Filter) ; 
4:   DataView dv = new DataView(ds.Tables["Products"], 
                           whereClause, "", 
                           DataViewRowState.CurrentRows) ; 
5:   return dv ; 
6: }

返回一个DataView对象,其中包含属于指定类别的产品。使用的DataView构造函数采用DataTable、类似SQL的where子句、排序表达式和DataViewRowState[4]。不需要DataRelations。

调试

我发现,在ItemDataBound方法上设置断点并利用Visual Studio .NET中的局部变量、监视和命令窗口来查找控件/对象非常有用。这有助于您找到要操作的控件和对象。

© . All rights reserved.