为什么我需要重新创建DataSource当我加载一个RDLC报告
本文关键字:加载 一个 报告 RDLC 创建 新创建 为什么 DataSource | 更新日期: 2023-09-27 18:18:03
我有一个MDI应用程序与许多不同的形式。然后我在ReportForm
中有一个ReportViewer
控件,我在其中动态加载RDLC报告。
通过单击按钮从其他表单打开ReportForm
。在ReportForm
中,在ReportViewer
控件之上,有一个ComboBox
,其中包含该特定表单的可用报告列表。该列表是基于打开ReportViewer的表单动态生成的。该列表是通过在Reports Project(输出为DLL)中查找与表单相关的文件夹生成的,该文件夹包含相应的.rdlc文件。
问题是:
由于RDLC都已经生成并配置了报告设计器,并绑定到特定的数据集和数据表,为什么我需要每次重新创建ReportDataSource对象(数据集,数据表)并将其重新绑定到报告?
我的实际代码:
// Code used to open a new ReportForm Window
private void bindingNavigatorViewReport_Click(object sender, EventArgs e)
{
// If the form is already open, then Focus on it
if (MdiMain.IsFormOpen(ApplicationForm.ReportForm))
{
Application.OpenForms[formName].Focus();
}
// I need to instantiate a new ReportForm
else
{
/* The parameters are:
* - ApplicationForm enum which identifies the Form;
* - The Form corresponding DataSet
*/
ReportForm reportForm = new ReportForm(ApplicationForm.SchoolForm, SchoolDataSet)
{
MdiParent = MdiParent,
Icon = Resources.ViewReportIcon
};
reportForm.Show();
}
}
// Code used to load report
/* In the ReportForm class I have a method that casts the parameters to the
* specific types. So I can obtain the DataSet to use.
*/
// Report Path inside DLL assembly taken from SelectedValue of ComboBox
string reportSource = cmbReport.SelectedValue.ToString();
// Get report Stream from DLL Path
Stream reportStream = assembly.GetManifestResourceStream(reportSource);
// Load report Stream
reportViewer1.LocalReport.LoadReportDefinition(reportStream);
/* Create a new DataSource with DataSet name and DataTable object
* The DataTable object must come from DataSet, ie: DataSet.SchoolListDataTable.
*/
ReportDataSource rds = new ReportDataSource("DataSetName", DataTableObject);
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(rds);
reportViewer1.LocalReport.Refresh();
主要问题是,我没有"动态的方式"从表单中获取与表单关联的每个报告的数据表对象,因为当我点击"打开报告窗口"按钮时,我有一个报告列表等数据集(与该表单关联),但许多不同的数据表,而不仅仅是一个。
** UPDATE:最终解决方案 **
最后,我发现当我加载报告流时,我可以使用以下代码:
// Loads all the data sources associated to the current selected report
IEnumerable<string> dsNames = reportViewer1.LocalReport.GetDataSourceNames();
foreach (string dsName in dsNames)
{
// dsName is equal to the string "V_REP_SCHOOLS" that is the corresponding DataTable name
ReportDataSource rds = new ReportDataSource(dsName, _currentReportDataSet.Tables[dsName]);
reportViewer1.LocalReport.DataSources.Add(rds);
}
加载报表流(查看上面的代码)后,GetDataSourceNames()
方法为我提供了在报表中命名的所有数据源(如果您查看报表设计器中的报表数据面板,则实际上是DataSet
)。因此,我将我的数据集命名为我需要加载数据的数据表,例如"V_REPORT_SCHOOLS",然后我从我的数据集按名称加载数据表。
主要思想是:您可以在报表和数据表名称之间建立映射,并通过名称简单地访问数据表。
您可以使用Tables
属性通过名称访问DataSet
中的数据表:
datasetInstance.Tables["SchoolListDataTable"]
所以在你的报告和数据表之间有一个映射就足够了。
对于这个映射,你可以使用设置或其他任何东西。例如,这个映射可以是一个简单的键值Dictionary<string,string>
,报告名称或,组合框中的名称为Key
,数据表名称为Value
:
var mapping = new Dictionary<string, string>();
mapping.Add("report1", "table1");
mapping.Add("report2", "table2");
,然后使用组合框的选定值从映射字典中检索所需的表名:
//Find selected report
var reportSource = cmbReport.SelectedValue.ToString();
//Load report definition
Stream reportStream = assembly.GetManifestResourceStream(reportSource);
reportViewer1.LocalReport.LoadReportDefinition(reportStream);
//I supppose you use whatever you put in combobox, as mapping key
//Find the table name
var tableName = mapping[reportSource];
//Set report data source
ReportDataSource rds = new ReportDataSource("DataSetName", datasetInstance.Tables[tableName]);
报告不存储数据集信息
创建报表时,选择数据源,以便设计器可以从中收集元数据(列名、数据类型等)。然后它几乎忘记了它,除了它创建了一个数据集文件(.xsd)。
从那里,当你加载报告,你需要初始化一个ReportDataSource
告诉它从哪里获得数据,因为报告本身(RDLC文件)不存储此信息。
可以把它看作一种关注点分离来防止耦合。我相信(不确定)这是为了让您可以在两个不同的位置(比如开发环境和生产环境)拥有两个相同的表模式,并将其指向其中任何一个。此外,我相信您可以将报告设置为从数据库以外的东西加载,例如xml文件,如果您愿意,这部分导致了另一个原因,它是这样的