今天被人问到这样一个问题:如何动态地切换报表中的图表类型,例如能不能同时支持柱状图和饼图,而且用户可以切换?
开发的环境是Reporting Service。
我为此做了一些研究,下面这个范例可以解释这个问题
为了做这个演示,我们需要在Northwind数据库中,准备一个特殊的存储过程,它可以根据国家统计出来销售额。
CREATE procedure [dbo].[SaleReportByCountry]
@Beginning_Date DateTime, @Ending_Date DateTime AS
SELECT Employees.Country,SUM([Order Subtotals].Subtotal) AS SaleAmount
FROM Employees INNER JOIN
(Orders INNER JOIN "Order Subtotals" ON Orders.OrderID = "Order Subtotals".OrderID)
ON Employees.EmployeeID = Orders.EmployeeID
WHERE Orders.ShippedDate Between @Beginning_Date And @Ending_Date
GROUP BY Employees.Country
【备注】为了简便演示的步骤,这里使用的模板是报表应用程序。这是VS2008的一个新的项目类型,基于Reporting Service
到这里为止,我们就创建好了一个报表应用程序。我们现在所使用的报表是所谓的本地报表(rdlc)。
运行该程序,查看效果
我们看到的报表,但没有数据,这是为什么呢?这是我们没有给报表绑定数据源。
将工具箱中的“SaleReportByCountryTableAdapter”拖动到窗体设计界面上,然后再到窗体的代码视图中添加一句代码
下面,我们为报表添加图表的功能。
从工具箱中拖拽“图表”到报表主体区域。
从数据源中拖放字段到图表上。默认的图表类型为“柱状图”。重新运行程序之后看到的效果如下
下面我们来思考的问题是如何切换图表类型。目前Reporting Service的API没有提供这方面的支持。我们现在要做就是直接修改rdlc文件的方式
rdlc其实是一个xml文件。如下
我们观察到,要修改报表类型的话,思路应该是要修改Report/Body/ReportItems/Chart[@Name=’chart1’]/Type属性
为了对比,我们专门添加了一个新的窗体,上面手工添加了几个控件,看起来就像下面这样
与此同时,我们将原先那个SalesReport.rdlc复制一份,粘贴之后重命名为“DynamicSalesReport.rdlc”,并且将该新文件的属性进行如下修改
这些都准备好了之后,我们可以编写Form2里面的代码
/// <summary>
/// 切换为柱状图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btChangeColumnChart_Click(object sender, EventArgs e)
{
ChangeChartType("Column");
}
/// <summary>
/// 切换为饼图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btChangePieChart_Click(object sender, EventArgs e)
{
ChangeChartType("Pie");
}
/// <summary>
/// 修改报表类型
/// 作者:陈希章
/// </summary>
/// <param name="type"></param>
private void ChangeChartType(string type)
{
XmlDocument doc = new XmlDocument();
doc.Load("DynamicSalesReport.rdlc");
XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
xnm.AddNamespace("x", "http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition");
xnm.AddNamespace("rd", "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");
doc.SelectSingleNode("/x:Report/x:Body/x:ReportItems/x:Chart[@Name='chart1']/x:Type", xnm).InnerText = type;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
doc.Save(ms);
ms.Position = 0;
reportViewer1.Reset();//一定要Reset才有效
reportViewer1.LocalReport.LoadReportDefinition(ms);
//增加一句代码,填充数据
saleReportByCountryTableAdapter1.Fill(northwindDataSet1.SaleReportByCountry, new DateTime(1996, 1, 1), new DateTime(1998, 1, 1));
Microsoft.Reporting.WinForms.ReportDataSource datasource = new Microsoft.Reporting.WinForms.ReportDataSource("NorthwindDataSet_SaleReportByCountry", northwindDataSet1.SaleReportByCountry);
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(datasource);
this.reportViewer1.RefreshReport();
ms.Close();
}
完成如上操作之后,就可以进行调试了
于是,整个世界清静了……