嵌套和分组的 Repeater





4.00/5 (4投票s)
2005 年 8 月 15 日
2分钟阅读

83643

974
创建一个使用嵌套ASP.NET中继器的数据驱动报表网页。
引言
使用嵌套的ASP.NET中继器,您可以轻松创建专业的报表样式网页,其中包含标准的ASP.NET控件。CodeProject上的其他文章展示了如何使用用户控件来实现这一点。此示例仅使用标准的Repeater控件,特别是ItemDataBound
方法来创建复杂的界面。
背景
我需要创建一个报表,但用户需要能够通过相同的界面更新它,因此SQL Reporting Services和Crystal Reports不适用。我不得不进行大量的研究才能解决一些问题;例如数据绑定语法、查找嵌套控件的技术,所以我决定分享我的成果。感谢在优秀的MSDN论坛上发布答案的人们。
安装
如果您想运行示例,请执行以下步骤
- 需要修改连接字符串以连接到您的数据库实例。
- 我包含了一个SQL脚本,该脚本创建报表存储过程。这需要针对Northwind数据库运行。
Data
存储过程从Northwind数据库返回两个结果集。
- 产品类别
- 产品和总销售额
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]在这里,我们检索产品名称,并将其用于传递到ImageButton
的CommandArgument
中[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中的局部变量、监视和命令窗口来查找控件/对象非常有用。这有助于您找到要操作的控件和对象。