在asp.net程式中,可以選擇使用水晶報表,功能確實強大。但是web版的水晶報表好像存在著作權的問題。如果所作報表不是複雜的一塌糊塗的話,可以使用微軟內建的Rdlc報表。
Rdlc優點:
1:Rdlc報表設計簡單
2:結果存成xml,易於控制
3:匯出格式作的很不錯
這裡所說的動態控制報表所指的是:在一些時候,製作了報表之後希望在運行中可以動態做一些小修改,比如說列的位置,使用者控制顯示那些列等等。
控制方法,嘗試了這麼幾種:
1:控制微軟提供的報表對象的屬性;
2:報表全部自動產生
3:修改報告源檔案,然後載入。
控制微軟提供的報表對象的屬性:基於這個功能需求,一開始我想到的方法是通過控制微軟提供的這些報表對象的屬性來實現。因為這種方法最人道了。但是事與願違,微軟的ReportViewer對象是用來顯示Report的,自然不行;我使用的report是自己設計的,localReport,找到Report對象,裡面方法有這個幾個:report.GetDefaultPageSettings();report.GetDocumentMap()等,第一個是擷取列印紙張德設定,第二個是擷取doc文檔(但是始終出錯),都是唯讀屬性;所以,第一種嘗試失敗。
第二種方法就是報表全部自動產生。可以找到一個完整的例子,在這裡:http://www.gotreportviewer.com/DynamicTable.zip
這個例子裡面,他把xml結構的rdlc報表寫成一個類ReportDefinition,然後通過自訂這個類的內容來得到一個報表。其實際還是為了自己構造一個報表對象的xml。這是載入自訂報表的過程:win下的代碼 this.reportViewer1.Reset();
this.reportViewer1.LocalReport.LoadReportDefinition(m_rdl);
this.reportViewer1.LocalReport.DataSources.Add(new ReportDataSource("MyData", m_dataSet.Tables[0]));
this.reportViewer1.RefreshReport();這是自動產生xml的代碼:
private MemoryStream GenerateRdl(List<string> allFields, List<string> selectedFields)
{
MemoryStream ms = new MemoryStream();
RdlGenerator gen = new RdlGenerator();
gen.AllFields = allFields;
gen.SelectedFields = selectedFields;
gen.WriteXml(ms);
ms.Position = 0;
return ms;
}
這是完全ReportDefinition的一部分定義:
namespace Rdl {
using System.Xml.Serialization;
/**//// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace=_
"http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition", IsNullable=false)]
public partial class Report {
private object[] itemsField;
但是幾經考慮之後,這個方案也不讓人滿意,原因是:所有的報表對象都得自己產生,一下子回到瞭解放前,沒有視覺化檢視的設計既繁瑣又複雜。特別是如果設計幾個line,然後再來上幾個分組的話,工作量巨大。
於是乎嘗試第三種方法:ReportVivwer載入報表前在記憶體中修改報告源檔案。這個方法比較狠,其實可以解決很多問題,包括設計自訂的列印紙張等(這裡有另外一種設定列印紙張的方法http://waxdoll.cnblogs.com/archive/2006/03/03/342435.html)。
設計思路是:首先載入rdlc檔案到一個XmlDocument對象;然後修改xml內容;把xml序列化成位元組流,交給ReportViewer顯示。
這是這一段代碼:
public MemoryStream GenerateRdlc()
{
XmlDocument sourceDoc = new XmlDocument();
string path = AppDomain.CurrentDomain.BaseDirectory + "Test/OrderList.rdlc";
sourceDoc.Load(path);
Hashtable reportColumns = GetReportColumns(sourceDoc.LastChild);
//just remove
for (int i = 0; i < reportColumns.Count; i++)
{
if (!FindReportCoulmns(reportColumns[i].ToString()))
{
RemoveColumnFromRdlc(sourceDoc.LastChild, i);
}
}
MemoryStream ms = new MemoryStream();
XmlSerializer serializer = new XmlSerializer(typeof(XmlDocument));
serializer.Serialize(ms, sourceDoc);
ms.Position = 0;
return ms;
}
至於如何GetReportColumns和RemoveColumnFromRdlc,那就很簡單了,就是一個操作xml對象的過程。比方說:
private Hashtable GetReportColumns(XmlNode root)
{
Hashtable cols = new Hashtable();
//XmlNamespaceManager s=new XmlNamespaceManager(
XmlNode cells = FindChildNode(root,"Body/ReportItems/Table/Header/TableRows/TableRow/TableCells");
for (int i = 0; i < cells.ChildNodes.Count; i++)
{
XmlNode cell =FindChildNode( cells.ChildNodes[i],"ReportItems/Textbox/DataElementName");
cols[i] = cell.InnerText;
}
return cols;
}
這是使用這一段的代碼:
this.ReportViewer1.LocalReport.LoadReportDefinition(this.Report.GenerateRdlc());
this.ReportViewer1.LocalReport.DataSources.Add(new ReportDataSource("DataSet1", result.Tables[0]));
this.ReportViewer1.LocalReport.Refresh();
這個方法終於成功了。
附:rdlc檔案的xml一段結構
xml結構
1<?xml version="1.0" encoding="utf-8"?>
2<Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
3 <DataSources>
4 <DataSource Name="ConnectionString">
5 <ConnectionProperties>
6 <ConnectString />
7 <DataProvider>SQL</DataProvider>
8 </ConnectionProperties>
9 <rd:DataSourceID>073016a7-6cb0-4e06-a6fd-f5882a039188</rd:DataSourceID>
10 </DataSource>
11 </DataSources>
12 <BottomMargin>2.5cm</BottomMargin>
13 <RightMargin>2.5cm</RightMargin>
14 <PageWidth>21cm</PageWidth>
15 <rd:DrawGrid>true</rd:DrawGrid>
16 <InteractiveWidth>21cm</InteractiveWidth>
17 <rd:GridSpacing>0.25cm</rd:GridSpacing>
18 <rd:SnapToGrid>true</rd:SnapToGrid>
19 <Body>
20 <ColumnSpacing>1cm</ColumnSpacing>
21 <ReportItems>
22 <Chart Name="chart1">