首页 > 代码库 > 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))]
ReportDefinition.cs

 

第二步:创建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的功能
View Code

 

第三步:提取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);                    }                }            }        }
提取DataGrid数据

 

第四步:填充数据

关键在设置ReportViewer类的LocalReport.ReportPath 和LocalReport.DataSources这两项。

未完,待续(不能把全部源代码贴出来,只写关键部分,一个代码稍稍有点长;另外,虽说全是我写的代码,但毕竟是跟别人打工的,贴出来算不算泄密,被公司开了咋办)

RDLC报表之动态生成报表