我有一个 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。
答案 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文件,如果你想要的话,这部分导致了另一个原因。