为什么在加载RDLC报告时需要重新创建DataSource?

时间:2015-10-16 10:48:03

标签: c# winforms reporting-services datatable datasource

我有一个 MDI应用程序,包含许多不同的表单。然后我在ReportViewer内部有一个ReportForm控件,我在其中动态加载RDLC报告。

点击按钮,从其他表单打开ReportForm。 在ReportForm内,在ReportViewer控件上方,有一个ComboBox,其中包含该特定表单的可用报告列表。该列表是根据打开ReportViewer的表单动态生成的。 通过在Reports Project(输出是DLL)中查找Form关联文件夹来生成列表,该文件夹包含相应的.rdlc文件。

问题是:

由于RDLC都已使用报表设计器生成和配置,并绑定到特定的DataSet和DataTable,为什么每次需要重新创建ReportDataSource对象(DataSet,DataTable)并将其重新绑定到报表?

我的实际代码:

// 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();

主要问题是我没有动态的方式"从表单中获取与表单关联的每个报表的DataTable对象,因为当我点击"打开报表窗口"按钮,我有一个报告列表等等DataSet(与该表格相关联),但有许多不同的DataTable,而不仅仅是一个。

** 更新:最终解决方案 **

最后我发现当我加载报告流时,我可以使用这段代码:

// 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()方法为我提供了所有DataSource(如果查看报表设计器中的“报表数据”面板,则显示DataSet)在报告中命名。 所以我将我的DataSet命名为DataTable,我需要从中加载我的数据,例如&#34; V_REPORT_SCHOOLS&#34;,然后我从我的DataSet中按名称加载了DataTable。

2 个答案:

答案 0 :(得分:1)

以下是主要想法:您可以在报告和数据表名称之间建立映射,只需按名称访问数据表。

您只需使用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]);

答案 1 :(得分:0)

报告不存储DataSet信息

在创建报表时,选择DataSource以便设计人员可以从中收集元数据(列名,数据类型等)。然后它几乎忘了它,除了它创建一个数据集文件(.xsd)。

当您加载报告时,您需要初始化ReportDataSource告诉它从哪里获取数据,因为报告本身(.rdlc文件)不存储此信息。

将其视为一种关注点的分离以防止耦合。我相信(不确定)这样你就可以拥有2个在两个不同位置相同的表格模式(比如说开发环境和生产环境),并指向它们中的任何一个。另外我相信你可以设置报告来加载除数据库之外的其他东西,比如xml文件,如果你想要的话,这部分导致了另一个原因。