• [转]RDLC报表——动态添加列


    本文转自:http://www.cnblogs.com/pszw/archive/2012/07/19/2599937.html

    前言

    最近接到一个需求:在给定的数据源中,某(些)列,可能需要单独统计,是否单独统计需要根据报表配置来决定。由于项目中一直使用RDLC来生成报表,临时为了一个需求换一种技术也不是很现实,所以自己捉摸了下。

    认识RDLC

    RDLC的主要有三个部分:

    (1)*.rdlc文件,本质是一个XML文件,这里定义了报表样式;

    (2)*.xsd文件,也是一个XML文件,这里定义了数据源格式;

    (3)*.aspx文件,呈现报表的web页面。

    注:RDLC是什么,可参考蜡人张的博客:http://www.cnblogs.com/waxdoll/archive/2006/02/25/337713.html

    如何实现动态

    (1)LocalReport对象提供了方法LoadReportDefinition(Stream stream)和属性ReportPath保证了我们不仅可以从流中读取文件,也可以指定本地文件路径加载rdlc文件;

    (2).rdlc,.xsd都是xml文件,可使用XmlDocument进行读写操作。

    实例

    下面实现一个学生成绩统计报表为例,介绍如何实现动态列。

    第一步 准备工作

    新建空web项目->添加xsd文件,创建一个table(文件名Students.xsd)->添加rdlc文件,与xsd的table关联,并绑定相关字段(文件名FirstRdlc.rdlc)。

    Students.xsd设计器视图:

    image

    对应的xml文件:

     View Source

    观察这段xml,会注意这段代码:

     <xs:element name="Class" msprop:Generator_ColumnVarNameInTable="columnClass" msprop:Generator_ColumnPropNameInRow="Class" msprop:Generator_ColumnPropNameInTable="ClassColumn" msprop:Generator_UserColumnName="Class" type="xs:string" minOccurs="0" />

    这句代码定义了报表数据源的“Class”这列。可想而知,我们如果动态添加一列,这里势必应该要修改。

    FirstRdlc.rdlc文件设计器视图:

    image

    对应的xml文件如下:

     View Source

    仔细观察这段xml文件,不难看出有几部分代码是值得关注的:

    (1)路径Report/DataSets/DataSet/Fields下得Field节点,这里定义的是同数据源相关的列;

     View Source

    (2)路径Report/DataSets/DataSet/rd:DataSetInfo节点,这里定义了rdlc关联的xsd文件的路径;

     View Source

    (3)路径Report/Body/ReportItems/Tablix/TablixBody/TablixColumns下的TablixColumn节点,这里应该定义了RDLC报表的列数

     View Source

    (4)路径Report/Body/ReportItems/Tablix/TablixBody/TablixRows下的TablixRow。从名称可知是报表行相关内容,其中每个TablixRow,又定义了单元格信息(在TablixCells下的TablixCell节点)。这里默认情况下有两行,第一行定义了报表列头显示内容,如:姓名,性别等,第二行定义了报表数据的绑定项。如:姓名绑定到xsd的Name字段。这里便有:<Value>=Fields!Name.Value</Value>

     View Source

    所以,这以上几处在我们修改xml时,势必可能需要修改。其实,这里还有一处需要修改,路径:Report/Body/ReportItems/Tablix/TablixColumnHierarchy/TablixMembers下的TablixMember,该节点个数一定要和报表列数相同。否则编译便会报错。

    第二步:操作XML,动态添加列(GPA列)

    (1)操作XML文件使用XmlDocument类,需要添加节点时,可以使用XmlNode.CloneNode(bool)方法。

     View Source

    (2)操作xsd文件,将需要添加的列,加入到xsd中,并保存指定路径(保存文件命名为Student1.xsd);

     View Source

    (2)修改rdlc文件,包括,待添加列、xsd文件路径等,中(或保存为rdlc文件);

    View Code
     1         /// <summary>
     2         /// 修改RDLC文件
     3         /// </summary>
     4         /// <returns></returns>
     5         private XmlDocument ModifyRdlc()
     6         {
     7             XmlDocument xmlDoc = new XmlDocument();
     8 
     9             xmlDoc.Load(AppDomain.CurrentDomain.BaseDirectory + "FirstRdlc.rdlc");
    10 
    11             //添加Field节点
    12             XmlNodeList fileds = xmlDoc.GetElementsByTagName("Fields");
    13 
    14             XmlNode filedNode = fileds.Item(0).FirstChild.CloneNode(true);
    15             filedNode.Attributes["Name"].Value = "GPA";
    16             filedNode.FirstChild.InnerText = "GPA";
    17             fileds.Item(0).AppendChild(filedNode);
    18 
    19             //添加TablixColumn
    20 
    21             XmlNodeList tablixColumns = xmlDoc.GetElementsByTagName("TablixColumns");
    22             XmlNode tablixColumn = tablixColumns.Item(0).FirstChild;
    23             XmlNode newtablixColumn = tablixColumn.CloneNode(true);
    24             tablixColumns.Item(0).AppendChild(newtablixColumn);
    25 
    26             //TablixMember
    27             XmlNodeList tablixMembers = xmlDoc.GetElementsByTagName("TablixColumnHierarchy");
    28 
    29             XmlNode tablixMember = tablixMembers.Item(0).FirstChild.FirstChild;
    30             XmlNode newTablixMember = tablixMember.CloneNode(true);
    31             tablixMembers.Item(0).FirstChild.AppendChild(newTablixMember);
    32 
    33             XmlNodeList tablixRows = xmlDoc.GetElementsByTagName("TablixRows");
    34 
    35             //TablixRows1
    36             var tablixRowsRowCells1 = tablixRows.Item(0).FirstChild.ChildNodes[1];
    37             XmlNode tablixRowCell1 = tablixRowsRowCells1.FirstChild;
    38             XmlNode newtablixRowCell1 = tablixRowCell1.CloneNode(true);
    39             var textBox1 = newtablixRowCell1.FirstChild.ChildNodes[0];
    40             textBox1.Attributes["Name"].Value = "GPA1";
    41 
    42             var paragraphs = textBox1.ChildNodes.Cast<XmlNode>().Where(item => item.Name == "Paragraphs").FirstOrDefault();
    43             paragraphs.FirstChild.FirstChild.FirstChild.FirstChild.InnerText = "GPA";
    44             var defaultName1 = textBox1.ChildNodes.Cast<XmlNode>().Where(item => item.Name == "rd:DefaultName").FirstOrDefault().InnerText = "GPA1";
    45 
    46             tablixRowsRowCells1.AppendChild(newtablixRowCell1);
    47 
    48             //TablixRows2
    49             var tablixRowsRowCells2 = tablixRows.Item(0).ChildNodes[1].ChildNodes[1];
    50             XmlNode tablixRowCell2 = tablixRowsRowCells2.FirstChild;
    51             XmlNode newtablixRowCell2 = tablixRowCell2.CloneNode(true);
    52             var textBox2 = newtablixRowCell2.FirstChild.ChildNodes[0];
    53             textBox2.Attributes["Name"].Value = "GPA";
    54 
    55             var paragraphs2 = textBox2.ChildNodes.Cast<XmlNode>().Where(item => item.Name == "Paragraphs").FirstOrDefault();
    56             paragraphs2.FirstChild.FirstChild.FirstChild.FirstChild.InnerText = "=Fields!GPA.Value";
    57             var defaultName2 = textBox2.ChildNodes.Cast<XmlNode>().Where(item => item.Name == "rd:DefaultName").FirstOrDefault().InnerText = "GPA";
    58 
    59             tablixRowsRowCells2.AppendChild(newtablixRowCell2);
    60 
    61             xmlDoc.Save(AppDomain.CurrentDomain.BaseDirectory + "FirstRdlc1.rdlc");
    62             return xmlDoc;
    63         }

     (3)将得到的XmlDocument实例,序列化到MemoryStream。

    复制代码
     1         /// <summary>
     2         /// 序列化到内存流
     3         /// </summary>
     4         /// <returns></returns>
     5         private Stream GetRdlcStream(XmlDocument xmlDoc)
     6         {
     7             Stream ms = new MemoryStream();
     8             XmlSerializer serializer = new XmlSerializer(typeof(XmlDocument));
     9             serializer.Serialize(ms, xmlDoc);
    10 
    11             ms.Position = 0;
    12             return ms;
    13         }
    复制代码

    第三步:加载报表,并显示

    (1)添加一个Page页面,并添加ReportView控件和ScriptManager控件,页面代码如下:

     View Source

    (2)加载报表定义,并绑定数据源(使用LoadReportDefinition(Stream stream)方法加载MemoryStream中信息)

    View Code
     1         /// <summary>
     2         /// 加载报表
     3         /// </summary>
     4         private void LoadReport()
     5         {
     6             //获取数据源
     7             DataTable dataSource = GetDataSource();
     8 
     9             //修改xsd文件
    10             ModifyXSD();
    11 
    12             //修改rdlc文件
    13             XmlDocument xmlDoc = ModifyRdlc();
    14 
    15             //将修改后的rdlc文档序列化到内存流中
    16             Stream stream = GetRdlcStream(xmlDoc);
    17 
    18             //加载报表定义
    19             rvDemo.LocalReport.LoadReportDefinition(stream);
    20             //rvDemo.LocalReport.ReportPath = "FirstRdlc.rdlc";
    21 
    22             //添加数据源,rvDemo是页面上的ReportView控件
    23             rvDemo.LocalReport.DataSources.Add(new ReportDataSource("dsStudent", dt));
    24             rvDemo.LocalReport.Refresh();
    25         }
    26 
    27         /// <summary>
    28         /// 获取数据源
    29         /// </summary>
    30         /// <returns></returns>
    31         private DataTable GetDataSource()
    32         {            
    33             //伪造一个数据源
    34             DataTable dt = new DataTable();
    35             dt.Columns.AddRange(new DataColumn[] 
    36                 { 
    37                     new DataColumn() { ColumnName = "RecId" }, 
    38                     new DataColumn() { ColumnName = "Name" }, 
    39                     new DataColumn() { ColumnName = "Age" }, 
    40                     new DataColumn() { ColumnName = "Class" }, 
    41                     new DataColumn() { ColumnName = "Scores" },
    42                     new DataColumn() { ColumnName = "GPA" }
    43                 });
    44 
    45             DataRow dr = dt.NewRow();
    46             dr["RecId"] = "1";
    47             dr["Name"] = "小明";
    48             dr["Age"] = "26";
    49             dr["Class"] = "1年级";
    50             dr["Scores"] = "90";
    51             dr["GPA"] = "4.0";
    52 
    53             dt.Rows.Add(dr);
    54             return dt;
    55         }

    如此,我们便可以动态的添加GPA这列到报表上了,结果如下:

    image

    源码地址:HelloRdlc.7z

    作者:ps_zw
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    毕业设计每日博客——第八周4
    毕业设计每日博客——第八周3
    毕业设计每日博客——第八周2
    毕业设计每日博客——第八周1
    毕业设计每日博客——第七周5
    毕业设计每日博客——第七周4
    毕业设计每日博客——第七周3
    毕业设计每日博客——第七周2
    毕业设计每日博客——第七周1
    毕业设计每日博客——第六周5
  • 原文地址:https://www.cnblogs.com/freeliver54/p/3555942.html
Copyright © 2020-2023  润新知