RDLC 报表开发 一、打开Visual Studio 2005,新建ASP.NET 网站,添加数据集,会自动调出数据集配置窗口TableAdapter 如果上面的窗口没有自动调出,可以如下图 可以调出上面的TableAdapter 窗口 二、新建立数据库连接 下面的这一步会将数据库连接保存到config 文件中 下面的这一步可以,选择生成SQL的方式 让我们先回到SQL Server Query Analyzer打开SQL Server 查询
器 在SQL程序中创建如下图的存储过程 然后回到 Visual Studio 2005,选择使用现在的存储过程,下一步,在这里,我们只需要选择所需要的存储过程,如刚才建立的EmployeeReport 即可完成TableAdapter向导的配置 三、添加报表项 创建报表项后,从左边工具栏拖动一个Table 到报表
器中,选择网站数据集中的字段,把它拖动到表格的列中,通过页眉页脚可以设置复杂的打印样式。 四、新建立一个ASPX页面,拖动一个Report Viewer控件到页面中,在ReportViewer任务窗口中,选择刚才建立的rdlc文件,生成解决
,然后执行就完成了报表开发。 [ 注意:如果此处报“未能找到在 ObjectDataSource ObjectDataSource1 的 TypeName 属性中指定的类型”的错误,说明数据源配置不正确,可以选择正确的配置即可。] 五、注意 1. 刚才的SQL 脚本 CREATE PROC EmployeeReport AS SELECT * FROM Employee GO 实际的报表开发中,一定不要用SELECT * ,只取报表中需要查看的字段。 2. 有时候,可能需要用户选择一些条件,有选择性的查看报表。而不是全部绑定数据 如上图,用户可能只需要查看2008-9-29至2008-9-30时间段之间的数据 则作法如下: 先建立好如上图的ASPX页面,在View Report 事件中写如下的程序 ReportViewer1.LocalReport.ReportPath = AppDomain.CurrentDomain.BaseDirectory + "/Report/Request.rdlc"; DateTime dtFrom =Convert.ToDateTime(txtDateFrom.Text); DateTime dtTo =Convert.ToDateTime(txtDateTo.Text); string requester = txtRequester.Text; string dept = txtRequestDept.Text; string material = ddlMaterial.SelectedValue; string iprstatus = ddlStatus.SelectedValue; DataTable reqrpt = ReportDB.RequestReport(dtFrom, dtTo, material, dept,requester, iprstatus); if (reqrpt != null) { ReportViewer1.LocalReport.DataSources.Clear(); ReportViewer1.LocalReport.DataSources.Add( new Microsoft.Reporting.WebForms.ReportDataSource("Request_RequestReport", reqrpt)); ReportViewer1.LocalReport.Refresh(); } ReportViewer1.LocalReport.Refresh(); 根据用户所选的参数,把数据值传到SQL语句中即可.下面是RequestReport方法的源码 DataTable RequestReport(DateTime dtFrom, DateTime dtTo, string pMaterial, string pDept, string pRequester, string pIPRStatus) { string MySQL = Purchase; string whDate = " RequestDate BETWEEN '{0}' AND '{1}' "; MySQL = MySQL + string.Format(whDate, dtFrom, dtTo); string whMaterial = " AND MaterialCode='{0}' "; if (pMaterial != "ALL") { MySQL = MySQL + string.Format(whMaterial, pMaterial); } string whDept = " AND RequestDepartment='{0}' "; MySQL = MySQL + string.Format(whDept, pDept); string whRequester=" AND Requester='{0}' "; if(pRequester!="ALL") MySQL = MySQL + string.Format(whRequester, pRequester); string whIPRStatus = " AND IPRStatus={0} "; if (pIPRStatus != "ALL") { MySQL = MySQL + string.Format(whIPRStatus, pIPRStatus); } IDataProvider privider = DataProvider.CreateDataProvider(); DataSet ds = privider.RetriveDataSet(MySQL); if (ds != null && ds.Tables.Count > 0) return ds.Tables[0]; else return null; } const string Purchase="SELECT SerialNO,LedgerAcc,CostCenter,Requester,"+ " RequestDate,RequestDepartment,MaterialCode, " + " Brand,Specifications,Unit,Quantity,Usage, "+ " ExpectedDeliveryDate,Currency "+ " ,Quotation1Supplier,Quotation1UnitPrice,Quotation1Amount, "+ " Quotation2Supplier,Quotation2UnitPrice,Quotation2Amount, "+ " Quotation3Supplier, Quotation3UnitPrice, Quotation3Amount, "+ " ProposedQuotationSupplier, ProposedQuotationUnitPrice, "+ " ProposedQuotationAmount,QuotationRemarks ,IPRStatus,QtyTo, UnitPriceTo FROM IPR WHERE "; 3. 设计报表时,可以用上述的方法,实际运行时,可以替换成SQL 语句,传到ReportDataSource中即可,只要相应的表结构字段是存在的。 4. 报表的定义是XML结构的,如果熟悉报表的定义格式
,可以用文本编辑器打开直接修改。 5. 如果采用SQL Server 2005的服务器端报表,可能还会有进一步的方便设计和开发的地方.这里采用的是.net framework的组件,客户端只需要安装.net framework2.0即可,无需安装额外的组件. ASP.NET中动态控制RDLC报表 在asp.net程序中,可以选择使用水晶报表,功能确实强大。但是web版的水晶报表好像存在版权的问
。如果所作报表不是复杂的一塌糊涂的话,可以使用微软自带的Rdlc报表。 Rdlc优点: 1:Rdlc报表设计简单 2:结果存成xml,易于控制 3:导出格式作的很不错 这里所说的动态控制报表所指的是:在一些时候,制作了报表之后希望在运行中可以动态的做一些小修改,比如说列的位置,用户控制显示那些列等等。 ReportVivwer加载报表前在内存中修改报表源文件。这个方法比较狠,其实可以解决很多问题,包括设计自定义的打印纸张等(这里有另外一种设置打印纸张的方法http://waxdoll.cnblogs.com/archive/2006/03/03/342435.html)。 设计思路是:首先加载rdlc文件到一个XmlDocument对象;然后修改xml内容;把xml序列化成字节流,交给ReportViewer显示。 这是这一段代码: public MemoryStream GenerateRdlc() { XmlDocument sourceDoc = new XmlDocument(); string path = AppDomain.CurrentDomain.BaseDirectory + "Test/OrderList.rdlc"; sourceDoc.Load(path); Hashtable reportColumns = GetReportColumns(sourceDoc.LastChild); //just remove for (int i = 0; i < reportColumns.Count; i++) { if (!FindReportCoulmns(reportColumns[i].ToString())) { RemoveColumnFromRdlc(sourceDoc.LastChild, i); } } MemoryStream ms = new MemoryStream(); XmlSerializer serializer = new XmlSerializer(typeof(XmlDocument)); serializer.Serialize(ms, sourceDoc); ms.Position = 0; return ms; } 至于如何GetReportColumns和RemoveColumnFromRdlc,那就很简单了,就是一个操作xml对象的过程。比方说: private Hashtable GetReportColumns(XmlNode root) { Hashtable cols = new Hashtable(); //XmlNamespaceManager s=new XmlNamespaceManager( XmlNode cells = FindChildNode(root,"Body/ReportItems/Table/Header/TableRows/TableRow/TableCells"); for (int i = 0; i < cells.ChildNodes.Count; i++) { XmlNode cell =FindChildNode( cells.ChildNodes[i],"ReportItems/Textbox/DataElementName"); cols[i] = cell.InnerText; } return cols; } 这是使用这一段的代码: this.ReportViewer1.LocalReport.LoadReportDefinition(this.Report.GenerateRdlc()); this.ReportViewer1.LocalReport.DataSources.Add(new ReportDataSource("DataSet1", result.Tables[0])); this.ReportViewer1.LocalReport.Refresh(); 这个方法终于成功了。 附:rdlc文件的xml一段结构 xml结构 1<?xml version="1.0" encoding="utf-8"?> 2<Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner"> 3 <DataSources> 4 <DataSource Name="ConnectionString"> 5 <ConnectionProperties> 6 <ConnectString /> 7 <DataProvider>SQL</DataProvider> 8 </ConnectionProperties> 9 <rd:DataSourceID>073016a7-6cb0-4e06-a6fd-f5882a039188</rd:DataSourceID> 10 </DataSource> 11 </DataSources> 12 <BottomMargin>2.5cm</BottomMargin> 13 <RightMargin>2.5cm</RightMargin> 14 <PageWidth>21cm</PageWidth> 15 <rd:DrawGrid>true</rd:DrawGrid> 16 <InteractiveWidth>21cm</InteractiveWidth> 17 <rd:GridSpacing>0.25cm</rd:GridSpacing> 18 <rd:SnapToGrid>true</rd:SnapToGrid> 19 <Body> 20 <ColumnSpacing>1cm</ColumnSpacing> 21 <ReportItems> 22 <Chart Name="chart1"> 使用ASP.NET2.0的ReportViewer查看RDLC报表 [字体:大 中 小] 介绍: 这篇文章是前天看园子里给的一个链接,具体是谁的我忘记了,只记得http://www.codeproject.com/aspnet/ReportViewer.asp这个地址被贴了出来,然后说因为什么原因就没翻译完。 我后来看了下正好对自己有用,因为公司里RS的东西有人在做,而楼下光电部门的BS需求也经常有,并且早就知道有这个东西只是一直没时间研究,正好找到这个文章,于是就好好的研究了一下午,先翻译一下,然后再补充点心得。 翻译的过程中尽量本地化了一下,不过保留了原文作者的意思。如果有翻译不贴切的地方请各位朋友批评指正。 在网上有很多关于SqlServer RS 的服务模式(Server Mode),而我在研究本地模式(Local Mode)确实用了很长的时间,尤其还是有参数调用的时候。 之所以要用本地模式而不是 服务器 模式,是因为服务模式的客户端每次请求一个报表的时候,服务器都要把数据组织成报表然后发送到客户端,虽然这样子安全些,但是巨型报表从服务器到浏览器的传输会降低其性能。 所以这个文章是描述如何组织报表并且用ASP.NET2.0的ReportViewer控件读取出来的,这里我们选用的就是本地模式,并且是使用带参数的 存储过程 。我所使用的是ASP.NET2.0,VisualStudio2005,还有SQLServer2005加Application Block。如果你没有 Microsoft Application Block这个工具,那么就请把示例中通过SQL Helper调用存储过程的代码换成SQL Command的就可以了。 在这里我们选用Northwind数据库,我们的示例展现给用户的就是让用户从下拉列表里选择货品名称然后在报表里筛选出信息来。 第一步,创建带参数的存储过程 ALTER PROCEDURE ShowProductByCategory(@CategoryName nvarchar(15) ) AS SELECT Categories.CategoryName, Products.ProductName, Products.UnitPrice, Products.UnitsInStock FROM Categories INNER JOIN Products ON Categories.CategoryID = Products.CategoryID WHERE CategoryName=@CategoryName RETURN 第二步,使用DataSet设计器创建一个DataSet下的DataTable 在 解决方案 管理器界面里,右键App_Code这个文件佳,选择”Add New Item”。在弹出的对话框里选择”DataSet”,给它起个名,比如DataSetProducts.xsd,然后点击”Add”按钮。这时候TableAdapter配置工具会自动出现,如果没有出现或者误将其关闭了的话,在DataSet设计器的任何一个地方点击鼠标右键,选择Add,然后再选择TableAdapter这个工具就会再次出现。根据向导来建立DataTable,在出现的界面中分别选择”User existing stored procedures”作为命令类型然后指定”ShowProductByCategory”作为Select命令。 在第一步创建的存储过程在第二步里就变成了一个DataTable,而报表数据就是通过这个DataTable提供的。 图一:包含一个DataTable的DataSetProducts.xsd就是报表的数据源 第三步:创建一个报表文件 在解决发方案管理器下右键选择Add New Item,然后选择Report模板。在这个示例里是直接用默认的名Report.rdlc的。rdl的意思是报表定义语言,c的意思就是客户端(client)。也就是说,rdl是个服务器报表,而rdlc是本地报表。 在工具箱里把Table拖拽到报表设计窗体中,这个”表”有三个部分,头,内容和尾。一个Table就是一个显示数据的区域,一个区域显示的是被绑定到的DataSet下的那些数据元素。尽管一个报表是可以拥有很多的区域的,但是,每个区域只能显示一个DataSet里的内容。基于这点,我们可以用存储过程来联合多张表的数据到一个DataSet里来填充报表。 图二:工具栏里的专门做报表模板的控件 打开”网站数据源”窗口,找到”DataSetProducts”数据集,就是在第二步里创建的那个。展开直到看到叫”ShowProductByCategory”的这个DataTable。这个Table叫这个名字是因为我们之前在TableAdapter配置向导里选择了“Use existing stored procedure”这项,并且我们的存储过程的名字就叫ShowProductByCategory。 在网站数据源窗口中依次把ProductName,UnitPrice和UnitsInStock这三项分别拽到报表设计器里显示细节的那一行,也就是中间那行的第一列,第二列和第三列。而且你可以右键单击任何一个显示细节行中的字段,然后在属性栏里找到Format标签来为Unit Price和Unit In Stock来定义它们的显示格式。 图三,网站数据源窗体显示了在你程序里定义的DataSet以及它们所拥有的列 第四步:在ASP.NET2.0页里加入ReportViewer控件 首先把DropDownList控件拽到表单里,然后用选择数据源选项的方法把Categories里的CategoryName字段进行绑定。在其它场景中 用户可以 通过其它方法比如文本框的方式来输入参数然后传递到存储过程当中。然后,把Report View控件拖拽到表单中,并且设置其Visible属性为False。还有需要注意的地方就是,ASP.NET2.0的Report Viewer提供 Excel 和PDF的导出方式,然而实际的过程中我发现,打印出来的报表和你设计时的样子总会有点误差。 图四,把这页设置成为StartUp页 下一步,调出Report Viewer的智能标签,选择刚才建立好的Report.rdlc文件。 图五,把报表定义文件联合到Report Viewer控件里。 第五步:写代码实现用户在下拉框选择不同的名称然后报表里显示不同的数据 这里不要忘记把Microsoft.Reporting.WebForms命名空间加入到你的code-behind(或code file)文件里。 1
using System; 2using System.Data; 3using System.Data.SqlClient; 4using System.Configuration; 5using System.Collections; 6using System.Web; 7using System.Web.Security; 8using System.Web.UI; 9using System.Web.UI.WebControls; 10using System.Web.UI.WebControls.WebParts; 11using System.Web.UI.HtmlControls; 12using Microsoft.ApplicationBlocks.Data; 13using Microsoft.Reporting.WebForms; 14 15public partial class ReportViewerLocalMode : System.Web.UI.Page 16{ 17 public string thisConnectionString = 18 ConfigurationManager.ConnectionStrings[ 19 "NorthwindConnectionString"].ConnectionString; 20 21 /**//*I used the following statement to show if you have multiple 22 input parameters, declare the parameter with the number 23 of parameters in your application, ex. New SqlParameter[4]; */ 24 25 public SqlParameter[] SearchValue = new SqlParameter[1]; 26 27 protected void RunReportButton_Click(object sender, EventArgs e) 28 { 29 //ReportViewer1.Visible is set to false in design mode 30 ReportViewer1.Visible = true; 31 SqlConnection thisConnection = new SqlConnection(thisConnectionString); 32 System.Data.DataSet thisDataSet = new System.Data.DataSet(); 33 SearchValue[0] = new SqlParameter("@CategoryName", 34 DropDownList1.SelectedValue); 35 36 /**//* Put the stored procedure result into a dataset */ 37 thisDataSet = SqlHelper.ExecuteDataset(thisConnection, 38 "ShowProductByCategory", SearchValue); 39 40 /**//*or thisDataSet = SqlHelper.ExecuteDataset(thisConnection, 41 "ShowProductByCategory", dropdownlist1.selectedvalue); 42 if you only have 1 input parameter */ 43 44 /**//* Associate thisDataSet (now loaded with the stored 45 procedure result) with the ReportViewer datasource */ 46 ReportDataSource datasource = new 47 ReportDataSource("DataSetProducts_ShowProductByCategory", 48 thisDataSet.Tables[0]); 49 50 ReportViewer1.LocalReport.DataSources.Clear(); 51 ReportViewer1.LocalReport.DataSources.Add(datasource); 52 if (thisDataSet.Tables[0].Rows.Count == 0) 53 { 54 lblMessage.Text = "Sorry, no products under this category!"; 55 } 56 57 ReportViewer1.LocalReport.Refresh(); 58 } 59}
第六步:运行报表 按F5键,单击”Run Report”按钮运行报表。 图六,运行报表 最后要确定ReportViewer被引入到网站中,并且要配置下web.config文件,它有可能是如下的格式:
当把有ReportViewer控件的网站项目部署到别的服务器的时候,你需要把C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages\ReportViewer\ReportViewer.exe这个文件拷贝出来,然后在目标服务器运行一下。 翻译心得:似乎做过的翻译中这个是最简单的了,不过可能也是作者说的比较简介明了。 学习心得:作者阐述了两种ReportViewer能接受的报表方式并且做了简单的分析。不过在实际项目中用Server Mode的可能会更多些吧,Local Mode做一些不是规模太大或者太复杂的报表还是可以的。 公司里有专门做RS的我知道,据说做就要做一周,运行的时候看编写的质量,十分钟是正常的,而超过三十分钟的话就可能需要考虑改算法了。听起来好恐怖,呵呵,不过,如果能用到楼下光电部门的报表需求的话,我想要比以前GridView to Excel的方式更舒服一些。 如果这个能研究明白的话打算做一个专门的入门视频讲解来帮助更多的人了解这个控件。