首页 > 代码库 > RDLC报表之动态生成报表
RDLC报表之动态生成报表
首先,必须感谢和致敬蜡人张前辈:
http://waxdoll.cnblogs.com/archive/2006/02/25/337713.html
2.微软GotReportViewer官方的案例:
http://www.gotreportviewer.com/(约有20来个,很详细。有时候会上不了)
)
前段时间,做了RDLC报表,主要是三块功能:
1、从DataGrid提取数据,然后创建对应的RDLC报表文件,以利用ReportViewer类的打印排版的功能(其中做了个提取数据的通用函数,可以提取任意控件的数据;只要拼接成DataTable这种网状的格子就好)
2、给一个简单的RDLC模板,以提供表头的字体格式和表内部数据等样式相关的信息,然后再用DataGrid里提取的数据,填充到报表里
3、做了一个TreeView,很简单;根据报表文件名称,切换左侧树上的Item,就加载不同的报表,显示数据。用了一点反射的知识
第一步:根据 Report Definition Language (RDL) 生成对应的类和命名空间。
1、去
http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition/
下载ReportDefinition2010.xsd。
注意:ReportDefinition和Visual Studio出的有个时间差,官网上有2005版和2008版。2005版,VS2008以后支持;2008版,VS2010以后支持。2010版,要VS2012
以后才支持。我的是VS2010,用了2008版。
2、找XML Schema Definition Tool (Xsd.exe),Windows操作系统会自带。For more detail,please refer to:
https://msdn.microsoft.com/en-us/library/x6c1kb0s(v=vs.110).aspx
Below is my CMD in administator mode:
C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64>xsd
/c /n:RDLC
/out:C:\Users\admin\Desktop\RDLCReportResearch
C:\Users\admin\Desktop\RDLCReportResearch\ReportDefinition.xsd
完了,生成的是这么个样子
using System.Xml.Serialization; /// <remarks/> [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition")] [System.Xml.Serialization.XmlRootAttribute(Namespace="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition", IsNullable=false)] public partial class Report { private object[] itemsField; private ItemsChoiceType80[] itemsElementNameField; private System.Xml.XmlAttribute[] anyAttrField; /// <remarks/> [System.Xml.Serialization.XmlAnyElementAttribute()] [System.Xml.Serialization.XmlElementAttribute("Author", typeof(string))] [System.Xml.Serialization.XmlElementAttribute("AutoRefresh", typeof(uint))] [System.Xml.Serialization.XmlElementAttribute("Body", typeof(BodyType))] [System.Xml.Serialization.XmlElementAttribute("Classes", typeof(ClassesType))] [System.Xml.Serialization.XmlElementAttribute("Code", typeof(string))] [System.Xml.Serialization.XmlElementAttribute("CodeModules", typeof(CodeModulesType))] [System.Xml.Serialization.XmlElementAttribute("ConsumeContainerWhitespace", typeof(bool))]
第二步:创建RDLCGenerator类和TablixRDLCGenerator类
根据下载的Report Definition Language(RDL)和一个创建的简单的RDLC文件,知道RDLC文件基本要有哪几部分组成;然后层层嵌套创建就出来了,很简单。
Tablix是关键数据区,GotReportViewer上面的例子,DynamicMatrix和DynamicTable是根据RDL2005来做的,RDL2008以后,就是一个Tablix:
/// table + matrix = tablix /// Microsoft 用一个tablix来支持Table(表), Matrix(矩阵) and List(列表)这三种报表项 /// 整合了table和matrix的功能
第三步:提取DataGrid的数据
从DataGrid主要拿单元格Width、数据、BindingPath和HeaderName。现在对于DataGridColumn用DataTemplate的不知道咋个提取BindingPath数据,对DataGridHyperlinkColumn也取不到BindingPath。希望有人能热心帮忙
/// <summary> /// DataGrid的转换器,从DataGrid里提取出数据源,以及HeaderName、Binding的Path和ActualWidth /// </summary> /// <param name="dataGrid">包含数据的DatGrid</param> /// <param name="dt">DataGrid数据源转换成的DataTable</param> /// <param name="headerNames">DataGridColumn.Header</param> /// <param name="bindingPaths"> DataGridBoundColumn.Binding.Path</param> public static void DataGridAdapter(this DataGrid dataGrid, DataTable dt, List<string> headerNames, List<string> bindingPaths, List<double> widths) { // 取出DataGridColumn的Header,BingdingPath,ActualWidth为构造rdlc文件准备数据 headerNames.Clear(); bindingPaths.Clear(); widths.Clear(); for (int index = 0; index < dataGrid.Columns.Count; index++) { headerNames.Add(dataGrid.Columns[index].Header as string); widths.Add(dataGrid.Columns[index].ActualWidth); //string tempBindingPath = ((dataGrid.Columns[index] as DataGridBoundColumn).Binding as Binding).Path.Path; string tempBindingPath = GetDataGridColumnBindingPath(dataGrid.Columns[index]); bindingPaths.Add(tempBindingPath); if (String.IsNullOrEmpty(tempBindingPath) == false) dt.Columns.Add(tempBindingPath, typeof(string)); } for (int rowIndex = 0; rowIndex < dataGrid.Items.Count; rowIndex++) { // 要显示后,才能取到数据 DataGridRow rowContainer = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex); // 因为Peformance问题,EnableRowVirtualization被设置为true,只加载要显示的数据 // 重新滚动,然后再重用这些DataGridRow if (rowContainer == null) { dataGrid.UpdateLayout(); dataGrid.ScrollIntoView(dataGrid.Items[rowIndex]); rowContainer = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex); } if (rowContainer != null) { DataGridCellsPresenter presenter = DataGridHelper.GetVisualChild<DataGridCellsPresenter>(rowContainer); if (presenter != null) { DataRow dr = dt.NewRow(); bool isLastRowAllEmpty = true; for (int columnIndex = 0; columnIndex < bindingPaths.Count; columnIndex++) { DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex); if (cell != null) { if (cell.Content is TextBlock) { //TODO: DataGridHyperlinkColumn取不到数据 dr[bindingPaths[columnIndex]] = (cell.Content as TextBlock).Text; if (!String.IsNullOrEmpty((cell.Content as TextBlock).Text)) isLastRowAllEmpty = false; } else if (cell.Content is CheckBox) { string value = http://www.mamicode.com/((cell.Content as CheckBox).IsChecked == true) ? "是" : "否"; dr[bindingPaths[columnIndex]] = value; } else if (cell.Content is ComboBox) { dr[bindingPaths[columnIndex]] = (cell.Content as ComboBox).Text; if (!String.IsNullOrEmpty((cell.Content as ComboBox).Text)) isLastRowAllEmpty = false; } } } if (dataGrid.CanUserAddRows && (rowIndex == dataGrid.Items.Count - 1)) { // 如果CanUserAddRows被设置为true,只有最后一行的数据都不为空(CheckBox不算作内),才把数据添加到DataTable if (isLastRowAllEmpty) { continue; } } dt.Rows.Add(dr); } } } }
第四步:填充数据
关键在设置ReportViewer类的LocalReport.ReportPath 和LocalReport.DataSources这两项。
未完,待续(不能把全部源代码贴出来,只写关键部分,一个代码稍稍有点长;另外,虽说全是我写的代码,但毕竟是跟别人打工的,贴出来算不算泄密,被公司开了咋办)
RDLC报表之动态生成报表