23
votes

Problem

When you create a report (RDLC) the datasource seems to be only this or that database. Is there any way to convince VS to establish a link to memory data source? Something similar to WPF databinding.

The issue is, I would like to create a report with just a few data (entered by user), the whole point is layout, I don't have massive amount of data. So installing DB, writing data to DB, and then fetching them just to show the report is huge overkill.

So, I am looking for ability to create a report from memory data.

Background

I would like to design a layout, add images, set styles, font colors, etc. and add no more than few parameters like "first name", "last name" (of user) and "text". User would enter those 3 values, get a flyer and print it X times. The layout has to be exact -- starting from paper size, the placement of images, size of fonts, etc.

Maybe there are better solutions than RDLC but it is built-in engine, and no matter how I search it always pops out in search results.

5

5 Answers

29
votes

The datasource for an RDLC report can be anything that implements IEnumerable. If it is an enumeration of objects, then the properties on the object become fields in the report.

The thing about reports is they have their own internal notion of what the dataset is. At design time you need to provide the report designer with a dataset to work with. The report ingests that dataset internally and it is used to design the report. The reality is the report itself doesn't care about the actual dataset. It only cares about its schema. However, at runtime the objects you provide to satisfy that dataset can come from anywhere, as long as they satisfy that same schema.

I have a little blog post from back in my MS days that shows a trick on how to get good design time support, and then at runtime provide the report with any data you want:

http://blogs.msdn.com/b/magreer/archive/2008/10/16/setting-the-datasource-for-a-report-at-runtime.aspx

update Microsoft has since deleted my blog, but I found it in the wayback machine

https://web.archive.org/web/20160204041848/http://blogs.msdn.com/b/magreer/archive/2008/10/16/setting-the-datasource-for-a-report-at-runtime.aspx

11
votes

I recently wrote a blog post on creating a reporting assembly and using it in a project. My reports accept a list of my classes as a datasource and dont read from the DB themselves.

If you have a look here:

http://wraithnath.blogspot.com/2011/02/visual-studio-2010-report-viewer-object.html

it should help. Basically you create a class library containing the datasources as VS 2010 has a real problem detecting object datasources. It works like 20% of the time which is why i decided to do it this way.

N

2
votes

You can definitely bind to DataTables. Since you can create DataTables by hand, that's one way to do this without a database.

Here's an example where we programmatically load an RDLC control in order to render a PDF, using DataTables:

Dim Viewer As New ReportViewer
Viewer.LocalReport.ReportPath = "Physicians\Patients\OrderPlacement\DownloadRx\RxPdf.rdlc"

Me.LoadReport(orderID, Viewer)

Dim Renderer As New Code.Reporting.RenderToPDF
Renderer.Save(Viewer, FileFullPath)

And here are the contents of LoadReport:

Private Sub LoadReport(ByVal orderID As Integer, ByVal viewer As ReportViewer)
    'This is adapted from here: http://www.codeproject.com/KB/reporting-services/RDLC_and_DataSet.aspx
    '--Setup
    viewer.LocalReport.DataSources.Clear()
    viewer.LocalReport.EnableHyperlinks = True

    '--Configure DataSources
    Dim DocumentData As New RxDocumentData(orderID)
    Me.SetupRxPdfDataSourceHeader(DocumentData, viewer)
    Me.SetupRxPdfDataSourceMetrics(DocumentData, viewer)
    Me.SetupRxPdfDataSourceOrderHeader(DocumentData, viewer)
    Me.SetupRxPdfDataSourceOrderItems(DocumentData, viewer)
    Me.SetupRxPdfDataSourceChainOfCustody(DocumentData, viewer)
    Me.SetupRxPdfDataSourcePreTreatmentWorkupOrderTags(DocumentData, viewer)
    Me.SetupRxPdfDataSourceTakeHomeMedicationsOrderTags(DocumentData, viewer)

    viewer.LocalReport.Refresh()
End Sub

And here's one of those little configuration methods:

Private Sub SetupRxPdfDataSourceHeader(ByVal data As RxDocumentData, ByVal viewer As ReportViewer)
    Dim Dset_Header As New ReportDataSource("Dset_Header", data.HeaderDataTable)
    viewer.LocalReport.DataSources.Add(Dset_Header)
End Sub

data.HeaderDataTable is just a strongly typed DataTable that we create programmatically and put data into by hand.

There's nothing special about the DataTable, but getting to the point where this code was functional probably took a solid week. Hope this helps.

1
votes

You can manually create a DataTable object, populate the Columns collection in there, then call NewRow(). Take the result of that and fill the fields, then pass it to Rows.Add(). That's what I've been doing (really don't like rdlc, it's so slow and clunky compared to html).

0
votes

Return a list of your business objects and add it as the data source:

ReportViewer.LocalReport.DataSources.Add(new ReportDataSource("Report", new List<ReportDto> { new ReportDto(businessObj) }));

ReportDto is a wrapper for your business object where all formatting, concatenations and other report related modifications are done. It emits only the properties you need for the report.

Then go to add data set and pick the ReportDto's namespace as the data source and pick ReportDto as the dataset. Now all the properties you have included in ReportDto will be available in the designer.