前言:
在阅读本篇文章前,我建议您先阅读我之前写的另一篇关于VS2005中如何将datast动态绑定到reportViewer的文章:VS2005+SQL2005 Reporting Service动态绑定报表(Web),因为该篇可以说是对上一篇的补充。
关于本例子的例程下载:https://files.cnblogs.com/carlwave/exdynamicreport.rar
目的:
通过代码生成ado.net DataSet,然后绑定到reportViewer,基本上实现完全代码化,动态化,使对报表操作更方便。
在上篇中我对如何使用ado.net DataSet动态绑定到reportViewer作了详细介绍,只是上篇中自己留下个疑问,就是对report这个xml文件本身的设计变得相当复杂,通过和网上朋友的交流以及查询资料,写了一个对报表xml文件操作的类,基本实现完全动态化报表操作。
对报表(*.rdlc)文件进行操作:
其实,要生成一个rdlc文件并绑定上数据是有很多方法的。
1、 静态:使用微软自带的向导生成dataset,绑定上报表。
2、 完全动态:由于rdlc文件原本就是一个XML文件,所以你可以完全自行在代码中生成一个xml文件,但是这个方案也不让人满意,原因是:所有的报表对象都得自己生成,没有可视化工具的设计既繁琐又复杂。特别是如果设计几个line,然后再来上几个分组的话,工作量巨大。
3、 部分动态:首先加载rdlc文件到一个XmlDocument对象;然后修改xml内容;把xml序列化成字节流,交给ReportViewer显示。该方案缺点在于每次运行都需要重新加载rdlc,修改,增加了代码复杂度和运算量。
4、 动态修改rdlc文件->静态调用:这个方案就是我这里要介绍的方案,该方案通过对已经生成的rdlc文件进行读写操作,动态加入了ado.net dataset生成的字段和数据源。
优点在于只需要在第一次和dataset数据源变化的时候对报表的数据源部分进行重新读写就可。
PS:关于完全动态和部分动态可以参考:http://www.weste.net/2006/5-29/15422156045.html
详细操作步骤:
1、 新建一个解决方案,增加一个Web项目。
2、 增加一个报表文件。(图)
3、 增加报表xml操作的RdlcDataSet类,这个类是我纯粹为了报表文件关于数据连接写的,由于使用性比较单一,实现了大部分功能,但是总的来说封装的不是最好,如果你要对报表文件有更多的需求,可以重新封装这个类,具体怎么调用看代码。
'------------------------------------------------------------------------------2
'--ClassName: RdlcDataSet3
'--Description: for reset the report file(*.rdlc),add the DataSets files and datasources4
'-- If you want to use this class, you should do:5
'-- First:Use Vs2005 to creat a report file(*.rdlc)6
'-- Second:create a ado.net dataset and pass it to this class7
'-- Third:run in your codes EX:Dim objRdlcDataSet As New RdlcDataSet8
'-- objRdlcDataSet.RdlcDataSetNew("Reports\temp.rdlc", "Northwind", "Northwind", dataset)9
'-- Your just need to run it only once.10
'--Input: ado.net dataset, DataSourceName,dataSetName 11
'--Output : 12
'--08/31/06 - Created (Fei) 13
'-- just run once14
'-- ex:Dim objRdlcDataSet As New RdlcDataSet15
'-- objRdlcDataSet.RdlcDataSetNew("Reports\temp.rdlc", "Northwind", "Northwind", dataset)16
'--17
'-- if you just want to add a dataset in exist datasets18
'-- ex:Dim objRdlcDataSet As New RdlcDataSet19
'-- objRdlcDataSet.RdlcFileCheck("Reports\temp.rdlc")20
'-- objRdlcDataSet.AddDataSet(DataSetName, DataSourceName, DataSetAdd)21

22
Imports System.Data23
Imports System.Data.SqlClient24
Imports System.Xml25
Imports System.IO26

27
Public Class RdlcDataSet28
Inherits System.Web.UI.Page29

30
Private mErrorMessage As String31
Private mXmlReport As XmlDocument32
Private mRdlcPath As String33
Private mNodeReport As XmlNode34

35
Public Property ErrorMessage() As String36
Get37
Return mErrorMessage38
End Get39
Set(ByVal Value As String)40
mErrorMessage = Value41
End Set42
End Property43

44
'the path of the *.rdlc45
'ex:"Report\temp.rdlc"46
Public Property RdlcPath() As String47
Get48
Return mRdlcPath49
End Get50
Set(ByVal Value As String)51
mRdlcPath = Value52
End Set53
End Property54

55
Public Property XmlReport() As XmlDocument56
Get57
Return mXmlReport58
End Get59
Set(ByVal Value As XmlDocument)60
mXmlReport = Value61
End Set62
End Property63

64
Public Property NodeReport() As XmlElement65
Get66
Return mNodeReport67
End Get68
Set(ByVal Value As XmlElement)69
mNodeReport = Value70
End Set71
End Property72

73
'for reset the rdlc file and add datasources and datasets74
'ex:objRdlcDataSet.RdlcDataSet("Reports\temp.rdlc", "Northwind", "Northwind", dataset)75
Public Function RdlcDataSetNew(ByVal RdlcPath As String, ByVal DataSourceName As String, ByVal DataSetName As String, ByVal DataSetAdd As DataSet) As Boolean76
Dim blnResult As Boolean77
blnResult = RdlcFileCheck(RdlcPath)78
If blnResult = False Then79
Return False80
Exit Function81
End If82
Call RdlcDataSetInit()83
Call AddDataSource(DataSourceName)84
Call AddDataSet(DataSetName, DataSourceName, DataSetAdd)85
End Function86

87
'for check the rdlc file88
'in this class it can only for the *.rdlc which is grnerate by VS200589
Public Function RdlcFileCheck(ByVal RdlcPath As String) As Boolean90
Dim strChkRdlc As String91
strChkRdlc = RdlcPath.Substring(RdlcPath.Length - 4, 4)92
strChkRdlc = strChkRdlc.ToLower93
'if not report file return false94
If strChkRdlc.CompareTo("rdlc") <> 0 Then95
Me.ErrorMessage = "File is not a report file.(With *.rdlc)"96
Return False97
Exit Function98
End If99
RdlcPath = Server.MapPath(RdlcPath)100
Dim xmlReport As New XmlDocument101
xmlReport.Load(RdlcPath)102
Dim nodeReport As XmlNode103
nodeReport = xmlReport.ChildNodes(1)104
If nodeReport.Name.CompareTo("Report") <> 0 Then105
Me.ErrorMessage = "File is not a report file grnerate by VS2005."106
Return False107
Exit Function108
End If109
Me.NodeReport = nodeReport110
Me.RdlcPath = RdlcPath111
Me.XmlReport = xmlReport112
Return True113
End Function114

115
'for Rdlc init116
'delete all datasets and datasources117
'and add new empty datasets and datasources118
Public Sub RdlcDataSetInit()119
Call DelReportNodes("DataSources")120
Call DelReportNodes("DataSets")121
Call AddReportNodes("DataSources")122
Call AddReportNodes("DataSets")123
Me.XmlReport.Save(Me.RdlcPath)124
End Sub125

126
Private Sub DelReportNodes(ByVal strDelName As String)127
Dim nodelistDel As XmlNodeList128
nodelistDel = Me.NodeReport.ChildNodes129
Dim elmDel As XmlElement130
Dim i As Int32131
For i = 0 To nodelistDel.Count - 1132
elmDel = nodelistDel.Item(i)133
If elmDel.Name.CompareTo(strDelName) = 0 Then134
Me.NodeReport.RemoveChild(elmDel)135
i = i - 1136
End If137
If i = nodelistDel.Count - 1 Then138
Exit For139
End If140
Next141
End Sub142

143
Private Sub AddReportNodes(ByVal strAddName As String)144
Dim elmAdd As XmlElement145
elmAdd = Me.XmlReport.CreateElement("", strAddName, "")146
elmAdd.SetAttribute("xmlns", Me.NodeReport.NamespaceURI)147
Me.NodeReport.AppendChild(elmAdd)148
End Sub149

150
'add datasource151
'xml:<DataSources>152
'<DataSource Name="DataSourceName">153
' <ConnectionProperties>154
' <ConnectString />155
' <DataProvider>SQL</DataProvider>156
' </ConnectionProperties>157
'</DataSource>158
'</DataSources>159
Public Sub AddDataSource(ByVal DataSourceName As String)160
Dim i As Int32161
Dim blnResult As Boolean = False162
Dim nodeDataSources As XmlNode = Me.NodeReport163
Dim nodelistAddDataSource As XmlNodeList164
nodelistAddDataSource = Me.NodeReport.ChildNodes165
Dim elmDataSources As XmlElement166
For i = 0 To nodelistAddDataSource.Count - 1167
elmDataSources = nodelistAddDataSource.Item(i)168
If elmDataSources.Name.CompareTo("DataSources") = 0 Then169
nodeDataSources = elmDataSources170
blnResult = True171
Exit For172
End If173
Next174
If blnResult = False Then175
Me.ErrorMessage = "node DataSources hasn't found"176
Exit Sub177
End If178
Dim elmDataSource As XmlElement179
elmDataSource = Me.XmlReport.CreateElement("DataSource")180
elmDataSource.SetAttribute("Name", DataSourceName)181
Dim elmConnectionProperties As XmlElement182
elmConnectionProperties = Me.XmlReport.CreateElement("ConnectionProperties")183
Dim elmConnectString As XmlElement184
elmConnectString = Me.XmlReport.CreateElement("ConnectString")185
Dim elmDataProvider As XmlElement186
elmDataProvider = Me.XmlReport.CreateElement("DataProvider")187
elmDataProvider.InnerText = "SQL"188
elmConnectionProperties.AppendChild(elmconnectstring)189
elmConnectionProperties.AppendChild(elmDataProvider)190
elmDataSource.AppendChild(elmConnectionProperties)191
nodeDataSources.AppendChild(elmDataSource)192
Me.XmlReport.Save(Me.RdlcPath)193
End Sub194

195
'--------------------------------------------------------------------------196
'--add datasets197
'--xml:198
'--<DataSets>199
'-- <DataSet Name="DataSetName"> 200
'-- <Fields> 201
'-- <Field Name="DataFieldName">202
'-- <DataField>DataFieldName</DataField>203
'-- </Field>204
'-- </Fields>205
'-- <Query>206
'-- <DataSourceName>DataSourceName</DataSourceName>207
'-- <CommandText>208
'-- </CommandText>209
'-- <Timeout>30</Timeout>210
'-- </Query>211
'-- </DataSet>212
'--</DataSets>213
'----------------------------------------------------------------------214
Private Sub AddDataSet(ByVal DataSetName As String, ByVal DataSourceName As String, ByVal dsAdd As DataSet)215
Dim i As Int32216
Dim blnResult As Boolean = False217
Dim nodeDataSets As XmlNode = Me.NodeReport218
Dim nodelistAddDataSource As XmlNodeList219
nodelistAddDataSource = Me.NodeReport.ChildNodes220
Dim elmDataSources As XmlElement221
For i = 0 To nodelistAddDataSource.Count - 1222
elmDataSources = nodelistAddDataSource.Item(i)223
If elmDataSources.Name.CompareTo("DataSets") = 0 Then224
nodeDataSets = elmDataSources225
blnResult = True226
Exit For227
Else228

229
End If230
Next231
If blnResult = False Then232
Me.ErrorMessage = "node DataSets hasn't found"233
Exit Sub234
End If235
Dim elmDataSet As XmlElement236
elmDataSet = Me.XmlReport.CreateElement("DataSet")237
elmDataSet.SetAttribute("Name", DataSetName)238
Dim elmFields As XmlElement239
elmFields = Me.XmlReport.CreateElement("Fields")240
Dim elmField As XmlElement241
For i = 0 To dsAdd.Tables(0).Columns.Count - 1242
elmField = Me.XmlReport.CreateElement("Field")243
elmField.SetAttribute("Name", dsAdd.Tables(0).Columns(i).ToString)244
Dim elmDataField As XmlElement245
elmDataField = Me.XmlReport.CreateElement("DataField")246
elmDataField.InnerText = dsAdd.Tables(0).Columns(i).ToString247
'Dim elmTypeName As XmlElement248
'elmTypeName = Me.XmlReport.CreateElement("rd:TypeName")249
'elmTypeName.InnerText = dsAdd.Tables(0).Columns(i).DataType.ToString250
elmField.AppendChild(elmDataField)251
'elmField.AppendChild(elmTypeName)252
elmFields.AppendChild(elmField)253
Next254
Dim elmQuery As XmlElement255
elmQuery = Me.XmlReport.CreateElement("Query")256
Dim elmDataSourceName As XmlElement257
elmDataSourceName = Me.XmlReport.CreateElement("DataSourceName")258
elmDataSourceName.InnerText = DataSourceName259
Dim elmCommandText As XmlElement260
elmCommandText = Me.XmlReport.CreateElement("CommandText")261
Dim elmTimeout As XmlElement262
elmTimeout = Me.XmlReport.CreateElement("Timeout")263
elmTimeout.InnerText = "30"264
elmQuery.AppendChild(elmDataSourceName)265
elmQuery.AppendChild(elmCommandText)266
elmQuery.AppendChild(elmTimeout)267
elmDataSet.AppendChild(elmFields)268
elmDataSet.AppendChild(elmQuery)269
nodeDataSets.AppendChild(elmDataSet)270

271
Me.XmlReport.Save(RdlcPath)272
End Sub273

274
End Class4、 在代码中生成ado.net dataset,动态调用报表,运行一次(运行一次即可,以后除非dataset的数据源变了,否则可以注释掉)
Partial Class exLoadReport2
Inherits System.Web.UI.Page3

4
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load5
If Not Page.IsPostBack Then6
LoadCustomersReport("Reports\Customers.rdlc", "Northwind", "dsCustomers")7
End If8
End Sub9

10
Private Function GetCustomers() As DataSet11
Dim dsGetCustomers As New DataSet12
Dim sqlGetCustomers As String = "SELECT * from Customers where city in (select city from Customers group by city having count(city)>=2)"13
Using connection As New SqlConnection("Data Source=(local);Initial Catalog=Northwind;User ID=sa;Password=;")14
Dim command As New SqlCommand(sqlGetCustomers, connection)15
Dim adpGetCustomers As New SqlDataAdapter(command)16
adpGetCustomers.Fill(dsGetCustomers, "dsGetCustomers")17
End Using18
Return dsGetCustomers19
End Function20

21
Private Sub LoadCustomersReport(ByVal RdlcPath As String, ByVal DataSourceName As String, ByVal DataSetName As String)22
'get the dataset23
Dim tmpDs As DataSet24
tmpDs = GetCustomers()25
'------------------------------------------------------------------26
'you must run these codes blew before the first time you load the report.27
'After that, if you haven't changer the ado.net dataset, you don't need 28
'to run it again.29
'------------------------------------------------------------------30
'reset the report file(*.rdlc) add 'DataSets' and 'DataSource'31

32
'Dim objRdlcDataSet As New RdlcDataSet33
'objRdlcDataSet.RdlcDataSetNew(RdlcPath, DataSourceName, DataSetName, tmpDs)34
'------------------------------------------------------------------35

36
'set the reportViewer37
rpvEx.ProcessingMode = ProcessingMode.Local38
Dim localReport As LocalReport39
localReport = rpvEx.LocalReport40
localReport.ReportPath = RdlcPath41
'Create a report data source for the sales order data42
Dim dsCustomers As New ReportDataSource()43
dsCustomers.Name = DataSetName44
dsCustomers.Value = tmpDs.Tables(0)45
localReport.DataSources.Add(dsCustomers)46
localReport.Refresh()47
End Sub48
End Class
5、 设计报表,增加一个table,在table的属性中输入dataset的名字,注意:这个名字必须和你写报表文件所使用的dataset名字相同,否则会报错,找不到dataset。(图)
6、 再次运行即可。
PS:例程中的报表文件加入了一些分组以及函数的调用,关于报表的使用我就不描述了,这方面的资料还是比较多的。写的比较仓促,欢迎大家给出意见。

浙公网安备 33010602011771号