WinForms ReportViewer 和多个报表定义文件






4.33/5 (2投票s)
您需要的所有信息,以使 WinForms ReportViewer 在 .rdlc 文件中显示报表。
引言
您是否曾经在 Visual Studio 中努力使用 WinForms ReportViewer
来显示报表,而不是使用向导设计的报表? 本文向您展示如何以编程方式设置 ReportViewer
以显示用户选择的(.rdlc)报表定义文件中标识的报表。
想象一下,您创建了一个 WinForms 应用程序,在该应用程序中,您设计了一个窗体以显示预定义的报表,并且您希望为用户提供选择要显示的报表的选项。 如果您的报表作为嵌入资源包含在应用程序中,这通常很简单,因为所有数据源、表定义、SELECT
查询和 DATA 在应用程序代码中都可用。 但是,由于报表定义嵌入在应用程序可执行文件中,因此编辑现有报表或添加新报表意味着您必须重建可执行文件并将其分发给应用程序的所有用户。 如果您所要做的只是发送一个新的 .rdlc 文件,将其保存到指定的网络文件夹“MyApp_Reports”中,然后,该报表立即在您的应用程序中可用,该怎么办?
使用代码
好的,让我们看看如何实现。您需要创建一个新窗体,其中包含一个 Splitter
控件、一个 ListView
控件和一个 ReportViewer
控件。 将 ListView
放入 Splitter
的左窗格,将 ReportViewer
放入右窗格。 将 ListView
和 ReportViewer 的“Dock
”设置为“Fill
”。 现在,在窗体的代码隐藏中,添加以下内容
Imports System.Xml
Imports System.IO
Imports System.Data.SqlClient.SqlDataAdapter
Public Class Form1
'This gets the path to the folder where the report .rdlc files are stored
Dim mReportsFolder As String = My.Settings.ReportsFolder
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'get a list of all the .rdlc files in the 'Reports' folder
Dim ReportsList() As String = _
Directory.GetFiles(mReportsFolder, "*.rdlc")
'this variable will hold the name of the report without the .rdlc extension
Dim sRptName As String
'for each of the files present in the folder add
'their names and paths into the listview control
For Each sRptPath As String In ReportsList
sRptName = Path.GetFileNameWithoutExtension(sRptPath)
Me.lvReports.Items.Add(sRptName, sRptPath)
Next
End Sub
如果您此时运行您的应用程序,您应该会看到列表视图控件填充了所选文件夹中存在的报表文件的名称。 现在,我们希望用户能够单击列表视图中的一个报表名称,并且我们的应用程序在报表查看器中显示所选报表。 为此,我们需要响应 ListView
的 Click
事件或 SelectedIndexChanged
事件。 我选择了后者; 因此,在您的代码中,添加以下内容
Private Sub lvReports_SelectedIndexChanged(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles lvReports.SelectedIndexChanged
If Me.lvReports.SelectedItems.Count = 0 Then Exit Sub
'ideally you would set the MultiSelect property of the Listview
'control to 'False' so the user can only select one report
'at a time but here I just get the first item
Dim lvi As ListViewItem = Me.lvReports.SelectedItems(0)
'my listview control sometimes fires this
'event when no item is selected, weird!
If lvi Is Nothing Then Exit Sub
'just in case there's a problem getting the data for a report
'I've used this boolean variable to allow us
'to skip the rendering of the report
Dim bSkipReport As Boolean = False
'let's now get the path to the report that the user selected
Dim rptPath As String = lvi.ImageKey
'Becasue the .rdlc report definition file is in fact an XML file
'we can now just get the bits we need to display the report,
'so let's load the file into an Xml document
Dim rptXML As New XmlDocument
rptXML.Load(sRptPath)
'get the connection string. Notice that the element
'is named 'ConnectString' not 'ConnectionString'
Dim sRptConnectionString As String = _
rptXML.GetElementsByTagName("ConnectString")(0).InnerText
'the SELECT command 's also available in the following element
Dim sRptCommandText As String = _
rptXML.GetElementsByTagName("CommandText")(0).InnerText
'the report needs to get its data from a pre-defined
'table that matches the SELECT command above
'but more about that in a minute. For now let's get its name
Dim sRptTableName As String = _
rptXML.GetElementsByTagName("rd:TableName")(0).InnerText
'the above table is contained within a dataset and is referenced by the report
'using the following format 'DataSetname_TableName'
Dim sRptDataSet_TableName As String = _
rptXML.GetElementsByTagName("DataSetName")(0).InnerText
'and the name of the dataset is...
Dim sDatasetName As String = _
rptXML.GetElementsByTagName("rd:DataSetName")(0).InnerText
'within the .rdlc file is the definition of the structure of the table
'in the form of a list of table columns or database fields
'so this next code fragment gets the field list
'and creates a new table having the relevant columns
Dim xmlFields As XmlNodeList = _
rptXML.GetElementsByTagName("Field")
Dim dt As New DataTable
dt.TableName = sRptTableName
For Each fld As XmlNode In xmlFields
Dim sFldName As String = fld.ChildNodes(0).InnerText
Dim sFldType As String = fld.ChildNodes(1).InnerText
Dim fldType As System.Type = Type.GetType(sFldType)
dt.Columns.Add(sFldName, fldType)
Next
'we've now finished with the xml file so we can dispose of it
rptXML = Nothing
'now we need to create the report's dataset and add the table to it
Dim mDataSet As DataSet = New DataSet(sDatasetName)
mDataSet.Tables.Add(dt)
'ok we're nearly there. All that's left to do is:
' - get the data into the table;
' - create the report's datasource; and
' - assign it to the report.
'but before we do that we clear out any previoulsy assigned datasource
Me.rptVwr.LocalReport.DataSources.Clear()
'and rest the ReportViewer to it's default settings
Me.rptVwr.Reset()
'now we create an SQL DataAdapter using
'the commandtext and connection from earlier
Try
Dim da As New SqlClient.SqlDataAdapter(sRptCommandText, _
sRptConnectionString)
da.Fill(mDataSet.Tables(sRptTableName))
Catch ex As Exception
MessageBox.Show("There was a problem getting the data for this report", _
"Report Data Error", _
MessageBoxButtons.OK, MessageBoxIcon.Warning)
bSkipReport = True
End Try
'we use a Try-catch block to trap an error getting the data
'if everything is OK let's go ahead and populate the report
If Not bSkipReport Then
'create a new report datasource
Dim rs As New Microsoft.Reporting.WinForms.ReportDataSource(_
sRptDataSet_TableName, mDataSet.Tables(sRptTableName))
'and assign it to the ReportViewer control
Me.rptVwr.LocalReport.DataSources.Add(rs)
'now assign the report definition file to the ReportViewer
Me.rptVwr.LocalReport.ReportPath = sRptPath
Me.rptVwr.LocalReport.DisplayName = _
Path.GetFileNameWithoutExtension(sRptPath)
'and finally get it to display the report and its data
Me.rptVwr.RefreshReport()
End If
End Sub
End Class
关注点
两点
- 在加载新报表文件之前,请始终记住发出
ReportViewer.Reset
命令,因为即使在调用Me.rptVwr.LocalReport.DataSources.Clear()
之后,ReportViewer
似乎仍保留先前数据源的名称。 - .rdlc 文件包含两个名为“DataSet”的不同元素。 这在 XML 中是允许的,因为这些元素是不同父元素的子元素。 无论如何,一个
dataset
元素引用容器数据集,而另一个用作指向表的“指针”。 这最初非常令人困惑,并且引起了很多挠头!
历史
- 版本 0.1 - 2009 年 4 月 20 日。