I want to reuse the same RDLC to display different tables depending on a format field. But my report does not show anything when the data source has the IEnumerable<IGrouping<string, Row>>
return type already grouped.
So if the users picks the format A, the report would display a table grouped by some columns and if the user picks the format B the report would display the table grouped by something else.
My plan B would be to simply pass the datasource as an Enumerable and then order by in the report itself, but I wanted to have all the logic in the code, not in the RDLC..
I am using custom Dataset to build the report as follows:
public byte[] GetReport(ReportFormat reportFormat)
{
MyReportDataSource myReportDataSource = GetMyReportDataSource(reportFormat);
ReportDataSource dsDetails = GetDetailsDataSource(myReportDataSource);
ReportDataSource dsRows = GetRowsDataSource(myReportDataSource);
LocalReport localReport = new LocalReport();
localReport.ReportPath = "pathToMyRdlc.rdlc";
localReport.DataSources.Add(dsDetails);
localReport.DataSources.Add(dsRows);
Warning[] warnings;
string encoding;
string fileNameExtension;
string[] streams;
byte[] reportBytes = localReport.Render("pdf", null, PageCountMode.Actual,
out mimeType, out encoding, out fileNameExtension, out streams, out warnings);
return reportBytes;
}
private MyReportDataSource GetMyReportDataSource(ReportFormat reportFormat)
{
MyReportDataSource r = new MyReportDataSource();
r.ReportFormat = ReportFormat.A;
//some test rows
Row row1 = new Row
{
Name = "Joe",
LastName = "Doe",
Age = 42
};
Row row2 = new Row
{
Name = "Jane",
LastName = "Doe",
Age = 26
};
Row row3 = new Row
{
Name = "Joe",
LastName = "Smith",
Age = 31
};
r.AddRow(row1);
r.AddRow(row2);
r.AddRow(row3);
return r;
}
private ReportDataSource GetDetailsDataSource(MyReportDataSource myReportDataSource)
{
//ReportDataSource only accepts dataTable or IEnumerable, use IEnumerable but with single element as workaround
List<MyReportDataSource> listSingleItem = new List<MyReportDataSource>();
listSingleItem.Add(myReportDataSource);
ReportDataSource detailsDataSource = new ReportDataSource("DSDetails", listSingleItem.AsEnumerable());
return detailsDataSource;
}
private ReportDataSource GetDeclarationRowsDataSource(MyReportDataSource myReportDataSource)
{
ReportDataSource rowsDataSource = new ReportDataSource("DSRows", myDataSource.Rows);
return rowsDataSource;
}
so basically I'm passing to the local report two datasources, one DSDetails
is for the details (where the specified format is) and the other DSRows
for an internal Enumerable which has the data I want to display in the table. This would be my custom datasource object
public class DeclarationReportDataSource
{
public ReportFormat ReportFormat { get; set; }
private decimal _totalAge;
public decimal TotalAge
{
get
{
return Math.Round(this._totalAge, 2);
}
}
private List<Row> _Rows = new List<Row>();
//HERE IS THE PROBLEM
//This is the method that returns an IEnumerable ordered by
//depending on the format
//There is no problem to display data if I return an IEnumerable<Row>
public IEnumerable<IGrouping<string, Row>> Rows
{
get
{
if (this.ReportFormat == ReportFormat.A)
{
return this._Rows.GroupBy(r => r.Name);
}
//else group by different field
return this._Rows.GroupBy(r => r.LastName);
}
}
public void AddRow(Row row)
{
this._Rows.Add(row);
this._totalAge += row.Age;
}
}
I'm pretty new with RDLC, so any guidance or good article on how to do something similar would be much appreciated. Thanks
UPDATE My table in the report is displaying 2 empty rows, so the group by in the code works good but the rows don't display anything. So I suspect I'm missing some concept on how to render grouped rows. I'll keep investigating.