RDLC报表之动态生成报表

Posted CoderBaby

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RDLC报表之动态生成报表相关的知识,希望对你有一定的参考价值。

前段时间,做了RDLC报表,主要是三块功能:

1、从DataGrid提取(包括最新的增删改)数据,自动生成对应的RDLC报表文件(以流的形式驻存在内存中),用ReportViewer类来展示、打印、排版、预览、分页

   提供一个提取任意控件数据的通用接口,然后拼接成DataTable这种网状的格子。DataGrid里修改、增加、删除等数据变动,立即同步更新到报表

2、给一个简单的RDLC模板,提供表头的字体格式和表内部数据等样式相关的信息,然后再用DataGrid里提取的数据,生成DataTable和其它必需信息,填充到报表里,

     自动调整报表格式

3、做了一个TreeView,很简单;根据报表文件名称,切换左侧TreeView的Item,就加载不同的报表,显示数据。用了一点反射的知识

 

转载请注明出处: https://www.cnblogs.com/NaughtyCat/p/auto-generate-report.html

 

第一步:根据 Report Definition Language (RDL) 生成对应的类和命名空间。

1、去 http://schemas.microsoft.com/sqlserver/reporting/2010/01/reportdefinition/ 下载ReportDefinition2010.xsd。

注意:ReportDefinition和Visual Studio发布的有个时间差,官网上有ReportDefinition2005版和ReportDefinition2008版。ReportDefinition2005版,VS2008及以后才支持;

ReportDefinition2008版,VS2010及以后支持。2010版,要VS2012以后才支持。我的是VS2010,用ReportDefinition2008版就好。

 

2、找XML Schema Definition Tool (Xsd.exe),Windows操作系统会自带(微软会自带很多功能强大的exe,要是开源就好了)。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

 完了,生成的是这么个样子(ReportDefinition2005的生成出来有8000行左右,ReportDefinition2008的及以后有10000多行,贴一部分,样子参照下面代码)

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类

1、根据下载的Report Definition Language(RDL)和一个创建的简单的RDLC文件,知道RDLC文件基本要有哪几部分组成;然后层层嵌套创建就出来了,很简单。

2-1、Tablix是关键数据区,GotReportViewer上面的例子,DynamicMatrix和DynamicTable是根据RDL2005来做的,RDL2008以后,就是一个Tablix:

2-2、Tablix的主要数据区域: TablixHierarchyType CreateTablixColumnHierarchy()和TablixHierarchyType CreateTablixRowHierarchy()

2-3、对于HeaderRow和DataRow关键就在下面的不同。

1         private LocIDStringWithDataTypeAttribute CreateTablixTextRunValue(bool isHeaderCell, string name)
2         {
3             LocIDStringWithDataTypeAttribute v = new LocIDStringWithDataTypeAttribute();
4             v.Value = isHeaderCell ? name : "=Fields!" + name + ".Value";
5             v.DataType = StringWithDataTypeAttributeDataType.String;
6             return v;
7         }
CreateTablixTextRunValue

 2-4、DataSet的名字一定要和ReportDataSource里的名字完全匹配

 

RdlcGenerator的Read和Write方法比较重要。

    /// table + matrix = tablix
    /// Microsoft 用一个tablix来支持Table(表), Matrix(矩阵) and List(列表)这三种报表项
    /// 整合了table和matrix的功能
View Code
       #region Properties

        // DataGrid 的DataGridColumn的Header
        private List<string> headerNames = new List<string>();
        public List<string> HeaderNames
        {
            get { return headerNames; }
        }

        // 对应DataGrid Binding的Path
        private List<string> fieldNames = new List<string>();
        public List<string> FieldNames
        {
            get { return fieldNames; }
        }

        // 对应DataGrid Column的ActualWdith(因为实际的窗口宽度会重新计算)
        private List<double> widths = new List<double>();
        public List<double> Widths
        {
            get { return widths; }
        }

        // 如果没有更新过页面设置,用ReportViewer的默认页面设置;否则用最新的页面设置
        public PageSettings PageSettings { get; set; }

        public string Headline { get; set; }

        public string DataSourceName { get; set; }

        public string DataSetName { get; set; }

        #endregion

        #region Methods

        // 一层套一层,把xml构造出来
        private Report CreateReport()
        {
            Report report = new Report();

            report.Items = new object[]
            {
                CreateDataSources(),
                CreateDataSets(),
                CreateBody(),
                CalcReportWidth(),
                CreatePage(),
            };
            report.ItemsElementName = new ItemsChoiceType80[]
            {
                ItemsChoiceType80.DataSources,
                ItemsChoiceType80.DataSets,
                ItemsChoiceType80.Body,
                ItemsChoiceType80.Width,
                ItemsChoiceType80.Page,
            };

            return report;
        }

        private DataSourcesType CreateDataSources()
        {
            DataSourcesType dataSources = new DataSourcesType();
            dataSources.DataSource = new DataSourceType[] { CreateDataSource() };
            return dataSources;
        }

        private DataSourceType CreateDataSource()
        {
            DataSourceType dataSource = new DataSourceType();
            dataSource.Name = String.IsNullOrEmpty(DataSetName) ? "TBReport" : DataSetName;
            dataSource.Items = new object[] { CreateDataSourceConnectionProperties() };
            return dataSource;
        }

        private ConnectionPropertiesType CreateDataSourceConnectionProperties()
        {
            ConnectionPropertiesType connectionProperties = new ConnectionPropertiesType();

            connectionProperties.Items = new object[]
            {
                "System.Data.DataSet",
                "/* Local Connection */",
            };
            connectionProperties.ItemsElementName = new ItemsChoiceType[]
            {
                ItemsChoiceType.DataProvider,
                ItemsChoiceType.ConnectString,
            };

            return connectionProperties;
        }

        private DataSetsType CreateDataSets()
        {
            DataSetsType dataSets = new DataSetsType();
            dataSets.DataSet = new DataSetType[] { CreateDataSet() };
            return dataSets;
        }

        // Query暂时就不要了
        private DataSetType CreateDataSet()
        {
            DataSetType dataSet = new DataSetType();
            // DataSetName写死就好
            dataSet.Name = "CustomerDataSet";
            dataSet.Items = new object[] 
            { 
                CreateDataSetFields(),
                CreateDataSetQuery(),
            };

            return dataSet;
        }

        private FieldsType CreateDataSetFields()
        {
            FieldsType fields = new FieldsType();

            // DataSet的具体field由DataGrid的Bingding的Path值决定
            if ((fieldNames != null) && (fieldNames.Count > 0))
            {
                fields.Field = new FieldType[fieldNames.Count];
                for (int index = 0; index < fieldNames.Count; index++)
                    fields.Field[index] = CreateDataSetField(fieldNames[index]);
            }

            return fields;
        }

        private FieldType CreateDataSetField(string fieldName)
        {
            FieldType field = new FieldType();
            field.Name = fieldName;
            field.Items = new object[]
            {
                fieldName,
                // CreateDataSetFieldValue(),
            };
            return field;
        }

        // 暂时DataType全部用String
        private StringWithDataTypeAttribute CreateDataSetFieldValue()
        {
            StringWithDataTypeAttribute value = new StringWithDataTypeAttribute();
            value.DataType = StringWithDataTypeAttributeDataType.String;
            return value;
        }

        private QueryType CreateDataSetQuery()
        {
            QueryType query = new QueryType();

            query.Items = new object[]
            {
                "TBReport",
                "/* Local Query */",
            };
            query.ItemsElementName = new ItemsChoiceType1[]
            {
                ItemsChoiceType1.DataSourceName,
                ItemsChoiceType1.CommandText,
            };

            return query;
        }

        private BodyType CreateBody()
        {
            BodyType body = new BodyType();

            body.Items = new object[]
            {
                "4.8in",                // Height
                CreateReportItems(),    // ReportItems
                CreateBodyStyle(),
            };
            return body;
        }


        private ReportItemsType CreateReportItems()
        {
            ReportItemsType reportItems = new ReportItemsType();

            // 这是关键数据区域
            TablixRdlcGenerator tablixGen = new TablixRdlcGenerator();
            tablixGen.ResetHeaderNames(HeaderNames);
            tablixGen.ResetFieldNames(FieldNames);

            List<string> tablixColumnWidths;
            DataGridHelper.CalcTablixColumnWidth(CalcReportWidth(), Widths, out tablixColumnWidths);
            tablixGen.ResetWidths(tablixColumnWidths);

            reportItems.Items = new object[] 
            { 
                CreateReportHeadlineTextbox(),
                tablixGen.CreateTablix()
            };


            return reportItems;
        }

        // 创建标题
        private TextboxType CreateReportHeadlineTextbox()
        {
            TextboxType headlineTextbox = new TextboxType();
            headlineTextbox.Name = "headlineTextbox";

            string left = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Left / 100.0).ToString() + "in";
            string width = (PageSettings == null) ? "17cm" :
                ((double)(PageSettings.PaperSize.Width - PageSettings.Margins.Left - PageSettings.Margins.Right) / 100.0).ToString() + "in";

            headlineTextbox.Items = new object[]
            {
                true,
                true,
                CreateHeadlineTextboxParagraphs(),
                left,
                "0.5cm",
                "1.0cm",
                width,
                CreateHeadlineTextboxStyle()

            };
            headlineTextbox.ItemsElementName = new ItemsChoiceType14[]
            {   
                ItemsChoiceType14.CanGrow,
                ItemsChoiceType14.KeepTogether,
                ItemsChoiceType14.Paragraphs,
                ItemsChoiceType14.Left,
                ItemsChoiceType14.Top,
                ItemsChoiceType14.Height,
                ItemsChoiceType14.Width,
                ItemsChoiceType14.Style
            };

            return headlineTextbox;
        }

        private ParagraphsType CreateHeadlineTextboxParagraphs()
        {
            ParagraphsType headlineParagraphs = new ParagraphsType();
            headlineParagraphs.Paragraph = new ParagraphType[] {CreateHeadlineTextboxParagraph()};
            return headlineParagraphs;
        }

        private ParagraphType CreateHeadlineTextboxParagraph()
        {
            ParagraphType pt = new ParagraphType();
            pt.Items = new object[]
            {
                CreateHeadlineTextRuns(),
                CreateHeadlineParagraphStyle()
            };
            pt.ItemsElementName = new ItemsChoiceType12[]
            {
                ItemsChoiceType12.TextRuns,
                ItemsChoiceType12.Style,
            };
            return pt;
        }

        private TextRunsType CreateHeadlineTextRuns()
        {
            TextRunsType trt = new TextRunsType();
            trt.TextRun = new TextRunType[] { CreateHeadlineTextRun() };
            return trt;
        }

        private TextRunType CreateHeadlineTextRun()
        {
            TextRunType trt = new TextRunType();

            trt.Items = new object[]
            {
                CreateHeadLineTextRunValue(),
                CreateHeadlineTextRunStyle()
            };
            trt.ItemsElementName = new ItemsChoiceType11[]
            {
                ItemsChoiceType11.Value,
                ItemsChoiceType11.Style
            };

            return trt;
        }

        private LocIDStringWithDataTypeAttribute CreateHeadLineTextRunValue()
        {
            LocIDStringWithDataTypeAttribute value = new LocIDStringWithDataTypeAttribute();
            value.Value = (Headline == null) ? "标题" : Headline;
            value.DataType = StringWithDataTypeAttributeDataType.String;
            return value;
        }

        private StyleType CreateHeadlineTextRunStyle()
        {
            StyleType st = new StyleType();

            st.Items = new object[]
            {
                "宋体",
                "14pt",
                "Bold",
            };
            st.ItemsElementName = new ItemsChoiceType4[]
            {
                ItemsChoiceType4.FontFamily,
                ItemsChoiceType4.FontSize,
                ItemsChoiceType4.FontWeight
            };

            return st;
        }

        private StyleType CreateHeadlineParagraphStyle()
        {
            StyleType st = new StyleType();
            st.Items = new object[] { "Center" };
            st.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.TextAlign };
            return st;
        }

        private StyleType CreateHeadlineTextboxStyle()
        {
            StyleType headlineStyle = new StyleType();

            headlineStyle.Items = new object[]
            {
                 CreateHeadlineTextboxBorder(),
                "2pt",
                "2pt",
                "2pt",
                "2pt"
            };
            headlineStyle.ItemsElementName = new ItemsChoiceType4[]
            {
                ItemsChoiceType4.Border,
                ItemsChoiceType4.PaddingLeft,
                ItemsChoiceType4.PaddingRight,
                ItemsChoiceType4.PaddingTop,
                ItemsChoiceType4.PaddingBottom
            };

            return headlineStyle;
        }

        private BorderType CreateHeadlineTextboxBorder()
        {
            BorderType headlineTextboxBorder = new BorderType();
            headlineTextboxBorder.Items = new object[] { "None" };
            headlineTextboxBorder.ItemsElementName = new ItemsChoiceType2[] { ItemsChoiceType2.Style };
            return headlineTextboxBorder;
        }

        private StyleType CreateBodyStyle()
        {
            return new StyleType();
        }

        /// <summary>
        /// 设置页面基本属性—页眉、页脚、页宽、页高、左边距、右边距等
        /// </summary>
        private PageType CreatePage()
        {
            PageType page = new PageType();

            // 根据微软官方文档,PaperSize.Height, PaperSize.Width and Margins的Left, Right, Top, Bottom are in hundredths of an inch.
            string pageHeight = (PageSettings == null) ? "29.7cm" : ((double)PageSettings.PaperSize.Height / 100.0).ToString() + "in";
            string pageWidth = (PageSettings == null) ? "21cm" : ((double)PageSettings.PaperSize.Width / 100.0).ToString() + "in";
            string leftMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Left / 100.0).ToString() + "in";
            string rightMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Right / 100.0).ToString() + "in";
            string topMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Top / 100.0).ToString() + "in";
            string bottomMargin = (PageSettings == null) ? "2cm" : ((double)PageSettings.Margins.Bottom / 100.0).ToString() + "in";

            // TODO:
            // 页眉、页脚(后面再做)
            page.Items = new object[]
            {
                //创建Header不能为空
                // CreatePageHeader(),
                pageHeight,
                pageWidth,
                leftMargin,
                rightMargin,
                topMargin,
                bottomMargin,
                "0.13cm",
            };
            page.ItemsElementName = new ItemsChoiceType77[]
            {
               // ItemsChoiceType77.PageHeader,
                ItemsChoiceType77.PageHeight,
                ItemsChoiceType77.PageWidth,
                ItemsChoiceType77.LeftMargin,
                ItemsChoiceType77.RightMargin,
                ItemsChoiceType77.TopMargin,
                ItemsChoiceType77.BottomMargin,
                ItemsChoiceType77.ColumnSpacing
            };

            return page;
        }

        /// <summary>
        /// PageHeader和PageFooter也只是TextRun里Value的数据不一样
        /// </summary>
        /// <returns></returns>
        private PageSectionType CreatePageHeader()
        {
            return new PageSectionType();
        }

        private PageSectionType CreatePageFooter()
        {
            return new PageSectionType();
        }

        /// <summary>
        /// 把Report序列化为流
        /// </summary>
        /// <param name="stream">根据Report序列化好的流</param>
        public void Write(Stream stream)
        {
            Write(stream, CreateReport());
        }

        public void Write(Stream stream, Report report)
        {
            new XmlSerializer(typeof(Report)).Serialize(stream, report);
        }

        public Report Read(Stream stream)
        {
            return (Report)new XmlSerializer(typeof(Report)).Deserialize(stream);
        }

        /// <summary>
        /// 把和DataGrid对应的rdlc模板文件反序列化为Report
        /// </summary>
        /// <param name="rdlcModelFilePath">和DataGrid对应的rdlc模板文件</param>
        /// <returns>反序列化之后的Report</returns>
        public Report Read(string rdlcModelFilePath)
        {
            using (var stream = new FileStream(rdlcModelFilePath, FileMode.Open))
            {
                return Read(stream);
            }
        }

        public void Write(string rdlcModelFilePath)
        {
            using (var stream = new FileStream(rdlcModelFilePath, FileMode.OpenOrCreate))
            {
                stream.SetLength(0);
                Write(stream);
            }
        }

        /// <summary>
        /// 计算Report的宽度,页宽 - 左边距 - 右边距
        /// </summary>
        /// <returns></returns>
        public string CalcReportWidth()
        {
            string reportWidth = String.Empty;
            const double size = 100.0;
            reportWidth = (PageSettings == null) ? "6.5in" :
                ((double)(PageSettings.PaperSize.Width - PageSettings.Margins.Left - PageSettings.Margins.Right) / size).ToString() + "in";
            return reportWidth;
        }
RdlcGenerator.cs
    public class TablixRdlcGenerator
    {
        #region Properties

        // DataGrid 的DataGridColumn的Header
        private List<string> headerNames = new List<string>();
        public List<string> HeaderNames { get { return headerNames; } }

        // 对应DataGrid Binding的Path
        private List<string> fieldNames = new List<string>();
        public List<string> FieldNames { get { return fieldNames; } }
        public string DataSetName { get; set; }

        // 对应DataGrid Column的ActualWidth
        private List<string> widths = new List<string>();
        public List<string> Widths
        {
            get { return widths; }
        }


        #endregion

        #region Methods

        private void ResetValues(List<string> p, List<string> v)
        {
            p.Clear();
            if (v != null)
            {
                p.AddRange(v);
            }
        }

        public void ResetHeaderNames(List<string> hns)
        {
            ResetValues(HeaderNames, hns);
        }

        public void ResetFieldNames(List<string> fns)
        {
            ResetValues(FieldNames, fns);
        }

        public void ResetWidths(List<string> widths)
        {
            ResetValues(Widths, widths);
        }

        /// <summary>
        /// 矩阵和Table对应的Tablix稍微有些不一样,如对于矩阵,TablixBody里的表头和数据项
        /// 一些值会拆分到TablixColumnHierarchy和TablixRowHierarchy里TablixMember--TablixHeader--CellContents--Textbox
        /// 对于DataGrid我们用最简单的Table就好
        /// </summary>
        /// <returns></returns>
        public TablixType CreateTablix()
        {
            TablixType tablix = new TablixType();
            tablix.Name = "dataGridTablix0报表与打印学习总目录

VB.NET ReportViewer 动态绑RDLC

在rdlc中如何设置报表项的间隔距离?

rdlc报表相关

[转]简单的动态修改RDLC报表页边距和列宽的方法

用linq和datatable巧妙应用于微软报表rdlc