zoukankan      html  css  js  c++  java
  • 动态生成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 SDKsWindowsv7.0ABinx64>xsd

    /c /n:RDLC  

    /out:C:UsersadminDesktopRDLCReportResearch

    C:UsersadminDesktopRDLCReportResearchReportDefinition.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";
                tablix.Items = new object[]
                {
                   // 创建TablixCorner不能创建个空的
                   // CreateTablixCorner(),
                    CreateTablixBody(),
                    CreateTablixColumnHierarchy(),
                    CreateTablixRowHierarchy(),
                    true,
                    true,
                    CreateDataSetName(),
                    // Top, Left, Height, Width可具体调整
                    // Top, Left ---> Location(距离左上角);Height, Width ---> Size
                    // (Tablix的大小,这个Width不管用,具体是由各个TablixColumn的Width之和决定)
                    "1.8cm",
                    "2cm",
                    "2cm",     
                    "17cm",
                    CreateTablixStyle(),
                };
                tablix.ItemsElementName = new ItemsChoiceType73[]
                {
                   // ItemsChoiceType73.TablixCorner,
                    ItemsChoiceType73.TablixBody,
                    ItemsChoiceType73.TablixColumnHierarchy,
                    ItemsChoiceType73.TablixRowHierarchy,
                    ItemsChoiceType73.RepeatColumnHeaders,
                    ItemsChoiceType73.RepeatRowHeaders,
                    ItemsChoiceType73.DataSetName,
                    ItemsChoiceType73.Top,
                    ItemsChoiceType73.Left,
                    ItemsChoiceType73.Height,
                    ItemsChoiceType73.Width,
                    ItemsChoiceType73.Style
                };
    
                return tablix;
            }
    
            /// <summary>
            /// non-essential element, so make it emtpy temprorily
            /// 看样子是表头行,纵向合并的单元格(如纵向两行合并为一行)等相关的
            /// </summary>
            /// <returns></returns>
            private TablixCornerType CreateTablixCorner()
            {
                return new TablixCornerType();
            }
    
            private TablixBodyType CreateTablixBody()
            {
                TablixBodyType tablixBody = new TablixBodyType();
                tablixBody.Items = new object[]
                {
                    CreateTablixColumns(),
                    CreateTablixRows(),
                };
                return tablixBody;
            }
    
            private void EnumHeaderNames(Action<int> act)
            {
                for (int i = 0; i < HeaderNames.Count; i++)
                {
                    act(i);
                }
            }
    
            private TablixColumnsType CreateTablixColumns()
            {
                TablixColumnsType tablixColumns = new TablixColumnsType();
    
                // 根据DataGridColumns的数量来决定创建几列,并且每列要把具体的宽度传进去
                tablixColumns.Items = new object[headerNames.Count];
                EnumHeaderNames(p =>
                {
                    tablixColumns.Items[p] = CreateTablixColumn(p);
                });
                return tablixColumns;
            }
    
            private TablixColumnType CreateTablixColumn(int index)
            {
                // Width of column,应该根据DataGridColumn.Width来具体设定,暂时给个固定值
                return new TablixColumnType() { Items = new object[] { Widths[index] } };
            }
    
            /// <summary>
            /// 对于DataGrid只应有两行,一行是Header,一行是数据
            /// 如果有求
            /// </summary>
            /// <returns>TablixRowsType</returns>
            private TablixRowsType CreateTablixRows()
            {
                TablixRowsType tablixRows = new TablixRowsType();
                tablixRows.Items = new object[]
                {
                    CreateTablixRowHeader(),
                    CreateTablixRowData(),
                };
                return tablixRows;
            }
    
            private TablixRowType CreateTablixRowType(bool isHeader)
            {
                TablixRowType trt = new TablixRowType();
                trt.Items = new object[]
                {
                    "0.23622in",    // Default height
                    CreateTablixCells(isHeader),    // Header的Cells的内容和Data的Cells的内容应该不同
                };
                return trt;
            }
    
            /// <summary>
            /// Tablix Header
            /// </summary>
            /// <returns></returns>
            private TablixRowType CreateTablixRowHeader()
            {
                return CreateTablixRowType(true);
            }
    
            private TablixRowType CreateTablixRowData()
            {
                return CreateTablixRowType(false);
            }
    
            private TablixCellsType CreateTablixCells(bool isHeaerCell)
            {
                TablixCellsType tablixCells = new TablixCellsType();
                // 根据DataGridColumns的数量来决定创建几个Cell, Header应传DataGridColumn.Header数据
                tablixCells.Items = new object[HeaderNames.Count];
                EnumHeaderNames(p =>
                {
                    tablixCells.Items[p] = CreateTablixCell(isHeaerCell, p);
                });
                return tablixCells;
            }
    
            private TablixCellType CreateTablixCell(bool isHeaderCell, int index)
            {
                TablixCellType tablixCell = new TablixCellType();
                // 基本的只要"CellContents"就够了
                tablixCell.Items = new object[] { CreateCellContentes(isHeaderCell, index) };
                return tablixCell;
            }
    
            private CellContentsType CreateCellContentes(bool isheaderCell, int index)
            {
                CellContentsType cellContents = new CellContentsType();
    
                // 对于DataGrid转换的rdlc,通常是一个Textbox。具体可以是Chart、Image、Line、Rectangle、Subreport等等
                cellContents.Items = new object[] { CreateTablixCellTextbox(isheaderCell, index) };
                cellContents.ItemsElementName = new ItemsChoiceType71[] { ItemsChoiceType71.Textbox };
    
                return cellContents;
            }
    
            private TextboxType CreateTablixCellTextbox(bool isHeaderCell, int index)
            {
                TextboxType tablixCellTextbox = new TextboxType();
                // 对于Header的Textbox可以复杂一点,多些字体、背景颜色等字段的定义
                // Data的简单点//isHeaderCell ? headerNames[index] : 
                tablixCellTextbox.Name = isHeaderCell ? "TB" + fieldNames[index] : fieldNames[index];
                tablixCellTextbox.Items = new object[]
                {
                    true,
                    true,
                    CreateTablixCellTextboxParagraphs(isHeaderCell, isHeaderCell ? headerNames[index] : fieldNames[index]),
                    CreateTablixCellTextboxStyle(),
                };
                tablixCellTextbox.ItemsElementName = new ItemsChoiceType14[]
                {
                    ItemsChoiceType14.CanGrow,
                    ItemsChoiceType14.KeepTogether,
                    ItemsChoiceType14.Paragraphs,
                    ItemsChoiceType14.Style,
                };
                return tablixCellTextbox;
            }
    
            private ParagraphsType CreateTablixCellTextboxParagraphs(bool isHeaderCell, string name)
            {
                ParagraphsType pt = new ParagraphsType();
                pt.Paragraph = new ParagraphType[] { CreateTablixCellTextboxParagraph(isHeaderCell, name) };
                return pt;
            }
    
            private ParagraphType CreateTablixCellTextboxParagraph(bool isHeaderCell, string name)
            {
                ParagraphType pt = new ParagraphType();
                pt.Items = new object[]
                {
                    CreateTablixCellTextboxParagraphTextRuns(isHeaderCell, name),
                    CreateTablixCellTextboxParagraphStyle(isHeaderCell),
                };
                pt.ItemsElementName = new ItemsChoiceType12[]
                {
                    ItemsChoiceType12.TextRuns,
                    ItemsChoiceType12.Style,
                };
                return pt;
            }
    
            private TextRunsType CreateTablixCellTextboxParagraphTextRuns(bool isHeaderCell, string name)
            {
                TextRunsType trt = new TextRunsType();
                trt.TextRun = new TextRunType[] { CreateTablixCellTextboxParagraphTextRun(isHeaderCell, name) };
                return trt;
            }
    
            private TextRunType CreateTablixCellTextboxParagraphTextRun(bool isHeaderCell, string name)
            {
                TextRunType trt = new TextRunType();
                trt.Items = new object[]
                {
                    CreateTablixTextRunValue(isHeaderCell, name),
                    CreateTablixTextRunStyle(isHeaderCell),
                };
                trt.ItemsElementName = new ItemsChoiceType11[]
                {
                    ItemsChoiceType11.Value,
                    ItemsChoiceType11.Style,
                };
                return trt;
            }
    
            // 数据项和Header的关键不一样就在这个了
            private LocIDStringWithDataTypeAttribute CreateTablixTextRunValue(bool isHeaderCell, string name)
            {
                LocIDStringWithDataTypeAttribute v = new LocIDStringWithDataTypeAttribute();
                v.Value = isHeaderCell ? name : "=Fields!" + name + ".Value";
                v.DataType = StringWithDataTypeAttributeDataType.String;
                return v;
            }
    
            private StyleType CreateTablixTextRunStyle(bool isHeaderCell)
            {
                StyleType st = new StyleType();
                string fontSize = isHeaderCell ? "11pt" : "10pt";
                string FontWeight = isHeaderCell ? "Bold" : "Default";
                st.Items = new object[]
                {
                    "宋体",
                    fontSize,
                    FontWeight,
                };
                st.ItemsElementName = new ItemsChoiceType4[]
                {
                     ItemsChoiceType4.FontFamily,
                     ItemsChoiceType4.FontSize,
                     ItemsChoiceType4.FontWeight,
                };
                return st;
            }
    
            // 暂时设为表头行“居中对齐”,数据行“靠左对齐”;后面可具体定制表头行和数据行的对齐方式
            private StyleType CreateTablixCellTextboxParagraphStyle(bool isHeaderCell)
            {
                StyleType st = new StyleType();
                st.Items = new object[] { isHeaderCell ? "Center" : "Left" };
                st.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.TextAlign };
                return st;
            }
    
            // *****************************
            // Header的Color和Style可以和数据不同,下面是默认的Sytle,可自定义
            //******************************
            private StyleType CreateTablixCellTextboxStyle()
            {
                StyleType st = new StyleType();
                st.Items = new object[]
                {
                     CreateTablixCellTextboxBorder(),
                     "2pt",
                     "2pt",
                     "2pt",
                     "2pt",
                };
                st.ItemsElementName = new ItemsChoiceType4[]
                {
                    ItemsChoiceType4.Border,
                    // ItemsChoiceType4.BackgroundColor, 默认数据没有BackgroundColor
                    ItemsChoiceType4.PaddingLeft,
                    ItemsChoiceType4.PaddingRight,
                    ItemsChoiceType4.PaddingTop,
                    ItemsChoiceType4.PaddingBottom,
                };
                return st;
            }
    
            private BorderType CreateTablixCellTextboxBorder()
            {
                BorderType bt = new BorderType();
                bt.Items = new object[]
                {
                    "Black",
                    "Solid",
                    "1pt"
                };
                bt.ItemsElementName = new ItemsChoiceType2[]
                {
                    ItemsChoiceType2.Color,
                    ItemsChoiceType2.Style,
                    ItemsChoiceType2.Width
                };
                return bt;
            }
    
            /// <summary>
            /// 按最简单的来,DataGrid对应的应该是有几个column创建几个TablixMember
            /// </summary>
            private TablixHierarchyType CreateTablixColumnHierarchy()
            {
                return new TablixHierarchyType() { Items = new object[] { CreateTablixColumnMembers() } };
            }
    
            private TablixMembersType CreateTablixColumnMembers()
            {
                TablixMembersType tmts = new TablixMembersType();
                tmts.TablixMember = new TablixMemberType[HeaderNames.Count];
                EnumHeaderNames(p =>
                {
                    tmts.TablixMember[p] = CreateTablixColumnMember();
                });
                return tmts;
            }
    
            // DataGrid的Column对应的TablixMember创建一个空的就行
            private TablixMemberType CreateTablixColumnMember()
            {
                return new TablixMemberType();
            }
    
            // DataGrid按最简单的默认的来,即创建2个TablixMember即可
            private TablixHierarchyType CreateTablixRowHierarchy()
            {
                return new TablixHierarchyType() { Items = new object[] { CreateTablixRowMembers() } };
            }
    
            private TablixMembersType CreateTablixRowMembers()
            {
                TablixMembersType tablixMembers = new TablixMembersType();
                tablixMembers.TablixMember = new TablixMemberType[]
                {
                    CreateTablixRowMember0(),
                    CreateTablixRowMember1(),
                };
                return tablixMembers;
            }
    
            private TablixMemberType CreateTablixRowMember0()
            {
                TablixMemberType tmt = new TablixMemberType();
    
                tmt.Items = new object[]
                {
                    CreateTablixRowMemberKeepWithGroup(),
                    true,
                };
                tmt.ItemsElementName = new ItemsChoiceType72[]
                {
                    ItemsChoiceType72.KeepWithGroup,
                    ItemsChoiceType72.RepeatOnNewPage,
                };
    
                return tmt;
            }
    
            private TablixMemberTypeKeepWithGroup CreateTablixRowMemberKeepWithGroup()
            {
                return TablixMemberTypeKeepWithGroup.After;
            }
    
            private TablixMemberType CreateTablixRowMember1()
            {
                TablixMemberType tmt = new TablixMemberType();
                tmt.Items = new object[] { CreateTablixRowMemberGroup() };
                tmt.ItemsElementName = new ItemsChoiceType72[] { ItemsChoiceType72.Group };
                return tmt;
            }
    
            private GroupType CreateTablixRowMemberGroup()
            {
                return new GroupType() { Name = "详细信息" };
            }
    
            /// <summary>
            /// ReportDataSource.Name和RDLC文件的DataSetNamey应保持一致
            /// 对于DataGrid构造的报表,可统一固定用"CustormerDataSet";
            /// DataSetName不需要作为参数传进来
            /// </summary>
            /// <returns>DataSet Name</returns>
            private string CreateDataSetName()
            {
                return String.IsNullOrEmpty(DataSetName) ? "CustomerDataSet" : DataSetName;
            }
    
            private StyleType CreateTablixStyle()
            {
                StyleType st = new StyleType();
                st.Items = new object[] { CreateTablixBorder() };
                st.ItemsElementName = new ItemsChoiceType4[] { ItemsChoiceType4.Border };
                return st;
            }
    
            // Tablix的外边框格式
            private BorderType CreateTablixBorder()
            {
                BorderType bt = new BorderType();
    
                bt.Items = new object[] 
                {
                    "Black",
                    "Solid",
                    "2pt"
                };
                bt.ItemsElementName = new ItemsChoiceType2[] 
                { 
                    ItemsChoiceType2.Color,
                    ItemsChoiceType2.Style,
                    ItemsChoiceType2.Width
                };
    
                return bt;
            }
    
            #endregion
        }
    TablixRdlcGenerator.cscs

    第三步:提取DataGrid的数据

    1、主要从DataGrid提取每个Column的Width、BindingPath、Header的Content和每个单元格的数据。数据填充DataTable的Rows, BindingPath填充DataTable的Columns,

    Header的Content用来作为报表Tablix的标题行。BindingPath,对于DataTemplate和DataGridHyperlinkColumn不知道咋个取提取数据.

    2、dataGrid.ScrollIntoView(dataGrid.Items[rowIndex])这个是关键。DataGrid用了一个虚拟啥子来着的(名字不重要,原理简单,计算机领域大量处理性能的都是用这个办法),就是复用界面显示,一个窗口里能装下的几十条RowContainer,每次滚动,人要看到的时候才重新提取新的要显示的数据。

    这样提取数万条记录时,界面不会卡,也不会占用很多内存,每次是要显示的时候才取几十条,一点点取。要用,才给,只给需要的那点。

          /// <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 = ((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这两项。

            /// <summary>
            ///  报表数据源发生变化时,及时更新显示报表控件的数据源
            /// </summary>
            /// <param name="reportDataModel">报表数据模型基类</param>
            public void ResetReportData(ReportDataModel reportDataModel)
            {
                if (reportDataModel != null)
                {
                    reportViewer.Reset();
                    reportViewer.LocalReport.DataSources.Clear();
                    reportViewer.Clear();
    
                    if (!reportDataModel.IsDataGrid)
                        reportViewer.LocalReport.ReportPath = reportDataModel.RDLCReportPath;
                    else
                    {
                        // 如果是DataGrid转换成的,直接从内存流里加载数据
                        if (reportDataModel.MsDataGrid != null)
                        {
                            reportViewer.LocalReport.LoadReportDefinition(reportDataModel.MsDataGrid);
                            // 用完就释放掉,流所占用的所有资源
                           // reportDataModel.MsDataGrid.Dispose();
                        }
                    }
                    reportViewer.LocalReport.DataSources.Add(reportDataModel.ReportDataSource);
                    reportViewer.RefreshReport();
                }
            }
    ResetReportData

    第五步:提供一个ReportHelper类

    具体拼接数据以及计算高度等,还有用另一套办法实现第二个功能。

    1、根据DataGrid每列的宽度,按百分比,重新设置每列的宽度。

     1         /// <summary>
     2         /// 根据DataGrid的Column的Actual Width来设置报表里对应Tablix的TablixColumn的宽度
     3         /// </summary>
     4         /// <param name="reportWidth">报表的总宽度</param>
     5         /// <param name="widths">DataGrid的Column的Actual Width</param>
     6         /// <param name="tablixColumnWidths">重新按百分比计算的TablixColumn的宽度列表</param>
     7         public static void CalcTablixColumnWidth(string reportWidth, List<double> widths, out List<string> tablixColumnWidths)
     8         {
     9             double totalWidth = 0.0;
    10             double originalTotalWidth = 0.0;
    11             List<double> rateColumnWidth = new List<double>();
    12             string unit = reportWidth.Substring(reportWidth.Length - 2, 2);
    13 
    14             // 取到报表宽度字符串除去单位in或者cm的数值
    15             Double.TryParse(reportWidth.Substring(0, reportWidth.Length - 2), out totalWidth);
    16 
    17 
    18             for (int index = 0; index < widths.Count; index++)
    19                 originalTotalWidth += widths[index];
    20 
    21 
    22             for (int index = 0; index < widths.Count; index++)
    23                 rateColumnWidth.Add(widths[index] / originalTotalWidth);
    24 
    25             tablixColumnWidths = new List<string>();
    26             tablixColumnWidths.Clear();
    27             for (int index = 0; index < widths.Count; index++)
    28                 tablixColumnWidths.Add((rateColumnWidth[index] * totalWidth).ToString() + unit);
    29         }
    CalcTablixColumnWidth

    2、把内存中的流读出来,生成对应的RDLC文件,我那里没调用。所以设置LocalReport.ReportPath换成reportViewer.LocalReport.LoadReportDefinition(reportDataModel.MsDataGrid);

     1         /// <summary>
     2         /// 把内存的流生成为rdlc文件
     3         /// </summary>
     4         /// <param name="rdlc">按rdlc格式构造成功的内存流</param>
     5         public static void DumpRdlc(MemoryStream rdlc)
     6         {
     7             string tempRdlcPath = AppDomain.CurrentDomain.BaseDirectory + @"../../../CommonReport/Templates/GeneratedDataGrid.rdlc";
     8             if (File.Exists(tempRdlcPath))
     9                 File.Delete(tempRdlcPath);
    10 
    11             using (FileStream fs = new FileStream(tempRdlcPath, FileMode.Create))
    12             {
    13                 rdlc.WriteTo(fs);
    14             }
    15         }
    DumpRdlc

    3、部分调用的代码——给一个简单的RDLC模板,以提供表头的字体格式和表内部数据等样式相关的信息,然后再用DataGrid里提取的数据,填充到报表里

     1         /// <summary>
     2         /// 将DataGrid的数据抽取出来,转换成rdlc报表,以实现对提供DataGrid的打印、预览、分页和页面布局等功能的支持
     3         /// 但需要提供一个rdlc报表的模板,必须包括页眉页脚,至少一列数据和标题,以便拿到数据的表头的
     4         /// style和数据项的style,这一列数据项必须是第一项(且第一项的表头和数据都完整提供了style)
     5         /// </summary>
     6         /// <param name="dataGrid">提供数据的DataGrid</param>
     7         /// <param name="reportViewer">要加载DataGrid数据的ReportViewer</param>
     8         /// <param name="rdlcModelFileName">rdlc模板的完整路径</param>
     9         /// <param name="headline">报表标题</param>
    10         public static void Print(this DataGrid dataGrid, CommonReport.Views.ReportViewer reportViewer, string rdlcModelFileName, string headline)
    11         {
    12             if (!File.Exists(rdlcModelFileName)) return;
    13 
    14             // 从DataGrid对应的rdlc模板里读出报表数据来
    15             Report report = null;
    16             string dataSourceName = DatasetName;
    17             dataGrid.UnderRdlcGenProc(reportViewer, headline, gen =>
    18             {
    19                 report = gen.Read(rdlcModelFileName);
    20 
    21                 // ReportDataSource的Name应该用取DataSet的Name
    22                 #region 取DataSourceName
    23 
    24                 DataGridHelper.ResetRdlcHeadline(report, headline);
    25                 for (int index = 0; index < report.Items.Length; index++)
    26                 {
    27                     if (report.Items[index] is DataSetsType)
    28                     {
    29                         DataSetsType dataSets = report.Items[index] as DataSetsType;
    30                         dataSourceName = dataSets.DataSet[0].Name;
    31                         break;
    32                     }
    33                 }
    34 
    35                 #endregion
    36             }, (gen, ms, dt) =>
    37             {
    38                 // 根据从DataGrid里提取的数据重新构造rdlc文件
    39                 RdlcReportAdapter(report, gen.HeaderNames, gen.FieldNames, gen.Widths);
    40                 gen.Write(ms, report);
    41                 return new Microsoft.Reporting.WinForms.ReportDataSource(dataSourceName) { Value = dt };
    42             });
    43         }
    Print

    4、打印的关于页面的一些默认设置(看情况)

    1             // 设置默认打印布局模式为“显示物理页”
    2             reportViewer.SetDisplayMode(DisplayMode.PrintLayout);
    3             reportViewer.ZoomMode = ZoomMode.Percent;
    4             reportViewer.ZoomPercent = 100;
    打印设置

    5、TreeView反射那块——功能三

     1         /// <summary>
     2         /// TreeView上选择的项发生变化时,根据所选TreeViewItem的Header信息和Tag里所存储的信息,利用反射构造对应报表的数据类实例
     3         /// 加载报表模板,调用委托将数据传到报表的显示控件上
     4         /// </summary>
     5         /// <param name="sender"></param>
     6         /// <param name="e"></param>
     7         private void RdlcTree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
     8         {
     9             if ((sender != null) && (sender is TreeView))
    10             {
    11                 if ((sender as TreeView).SelectedItem is TreeViewItem)
    12                 {
    13                     TreeViewItem tempItem = (sender as TreeView).SelectedItem as TreeViewItem;
    14                     if (tempItem.Tag is TreeViewItemDataType)
    15                     {
    16                         TreeViewItemDataType tempTreeViewDataType = tempItem.Tag as TreeViewItemDataType;
    17                         // 报表类型
    18                         if (tempTreeViewDataType.UserControlType == TreeViewItemDataType.ControlType.Report)
    19                         {
    20                             string reportDataModelInstanceName = tempItem.Header + "Model";
    21                             Type type = typeof(ReportDataModel);
    22                             Assembly assembly = type.Assembly;
    23                             try
    24                             {
    25                                 ReportDataModel reportDataModelInstance = (ReportDataModel)assembly.CreateInstance(type.Namespace + "." + reportDataModelInstanceName);
    26                                 if (reportDataModelInstance != null)
    27                                 {
    28                                     reportDataModelInstance.RDLCReportPath = (tempItem.Tag as TreeViewItemDataType).FullPath;
    29                                     reportDataModelInstance.InitDataSource();
    30                                     if (Viewer != null) 
    31                                         Viewer.ResetReportData(reportDataModelInstance);
    32                                 }
    33                             }
    34                             catch (Exception ex)
    35                             {
    36                                 MessageBox.Show(ex.Message);
    37                             }
    38                         }
    39 
    40                         // DataGrid 类型
    41                         else if (tempTreeViewDataType.UserControlType == TreeViewItemDataType.ControlType.DataGrid)
    42                         {
    43                             Type type = this.GetType();
    44                             Assembly assembly = type.Assembly;
    45                             try
    46                             {
    47                                 UserControl dataGridUserControlInstance = (UserControl)assembly.CreateInstance(type.Namespace + ".DataGrid." + tempItem.Header);
    48                             }
    49                             catch (Exception ex)
    50                             {
    51                                 MessageBox.Show(ex.Message);
    52                             }
    53                         }
    54                     }
    55                 }
    56             }
    57         }
    RdlcTree_SelectedItemChanged

    6、通过VisualTreeHelper找到指定类型的子或者父的方法,可在WPF里通用

            /// <summary>
            /// 找出子Visual的特定类型的Parent
            /// </summary>
            /// <typeparam name="T">指定类型</typeparam>
            /// <param name="child">继承自Visual的基本控件类型的子Visual</param>
            /// <returns></returns>
            public static T GetParent<T>(Visual child) where T : Visual
            {
                T parent = default(T);
                Visual visual = VisualTreeHelper.GetParent(child) as Visual;
                parent = visual as T;
                if (parent == null)
                    return GetParent<T>(visual);
                else
                    return parent;
            }
    
            /// <summary>
            /// 遍历取父控件的子Viusal,取到指定类型的子Viusal
            /// </summary>
            /// <typeparam name="T">T是Visual或其子类(基本上WPF的控件都是Visual的子类),指定子类型</typeparam>
            /// <param name="parent">父控件</param>
            /// <returns>子Viusal</returns>
            public static T GetVisualChild<T>(Visual parent) where T : Visual
            {
                T child = default(T);
                int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    
                for (int i = 0; i < numVisuals; i++)
                {
                    Visual visual = (Visual)VisualTreeHelper.GetChild(parent, i);
                    child = visual as T;
                    if (child == null)
                        child = GetVisualChild<T>(visual);
                    else
                        break;
                }
                return child;
            }
    VisualTreeHelper

    7、提供一个数据深拷贝的通用方法(C#类以及除基类型之外,好多都是传引用,这个是地址,值拷贝不好搞,这个方法直接拷贝流,但是必须类的每个字段都支持序列化)

     1         /// <summary>
     2         /// 对引用类型的数据——“所有字段都加了Serializable特性,以支持序列化”
     3         /// 利用序列化和反序列化实现深度拷贝,即拷贝了堆上的数据,搞了个堆的副本
     4         /// 而不是浅拷贝那样,只是拷贝了一个指向数据堆的内存地址
     5         /// 非常实用的小函数,支持所有引用类型数据
     6         /// </summary>
     7         /// <param name="original">要拷贝的引用类型数据源</param>
     8         /// <returns>源数据的副本</returns>
     9         public static object DeepColne(Object original)
    10         {
    11             // 构造一个临时的内存流
    12             using (MemoryStream ms = new MemoryStream())
    13             {
    14                 // 调用BinaryFormatter来完成复杂的序列化和反序列化工作
    15                 BinaryFormatter formatter = new BinaryFormatter();
    16 
    17                 // StreamingContext—描述给定的序列化流的源和目标,并提供一个由调用方定义的附加上下文
    18                 formatter.Context = new StreamingContext(StreamingContextStates.Clone);
    19 
    20                 // 把对象图序列化到内存流,original的每个字段必须标记为可序列化,否则会出错
    21                 formatter.Serialize(ms, original);
    22 
    23                 // 反序列化之前需要设置流的当前位置为最开始的位置
    24                 ms.Position = 0;
    25 
    26                 // 把内存流反序列化为对象图,再以基类的形式返回给调用者
    27                 return formatter.Deserialize(ms);
    28             }
    29         }
    DeepColne

    六、运行效果

    1、含有DataGrid或者其它控件的界面

    2、点击打印后,报表生成

    附:

    1、ReportItems!具体RDLC报表上控件的名称.Value这个取到报表设计器里任意项的数据,然后就可在表达式里进行各种逻辑运算。例如:

    = ReportItems!forestryMaintenance.Value + ReportItems!pension.Value + ReportItems!SumPolicy.Value
    + ReportItems!livingExpenses.Value + ReportItems!resettlement.Value

    2、合并单元格,纵向和横向的

    这个要分组,具体请搜索网上资源

    3、控制每页都显示

    对于标题,设置KeepWith属性和Tablix一起出现就好;还有一个办法,是设置其它的属性,暂时忘了,网上有

    4、XML很重要,据目前所知,微软的工程文件、WPF、打印、报表、XPS、Office2007以后版本等,XML都是基石。(未完,待续)

    5、页面纸张尺寸(PageSetting里的一些关于大小的值,单位都是1/100 inch;页面设置布局排版打印有点麻烦,稍不注意就多出去一点,字体、页眉、页脚、边框、页边距等),如下图:

     6、border style

    末了,必须感谢和致敬蜡人张前辈:

    http://waxdoll.cnblogs.com/archive/2006/02/25/337713.html

    2.微软GotReportViewer官方的案例:

    http://www.gotreportviewer.com/(约有20来个,很详细。有时候会上不了)

  • 相关阅读:
    LeetCode Find Duplicate File in System
    LeetCode 681. Next Closest Time
    LeetCode 678. Valid Parenthesis String
    LeetCode 616. Add Bold Tag in String
    LeetCode 639. Decode Ways II
    LeetCode 536. Construct Binary Tree from String
    LeetCode 539. Minimum Time Difference
    LeetCode 635. Design Log Storage System
    LeetCode Split Concatenated Strings
    LeetCode 696. Count Binary Substrings
  • 原文地址:https://www.cnblogs.com/NaughtyCat/p/auto-generate-report.html
Copyright © 2011-2022 走看看