RDLC報表——動態添加列


前言

最近接到一個需求:在給定的數據源中,某(些)列,可能需要單獨統計,是否單獨統計需要根據報表配置來決定。由於項目中一直使用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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM