为什么我需要重新创建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",然后我从我的数据集按名称加载数据表。

为什么我需要重新创建DataSource当我加载一个RDLC报告

主要思想是:您可以在报表和数据表名称之间建立映射,并通过名称简单地访问数据表。

您可以使用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文件,如果您愿意,这部分导致了另一个原因,它是这样的