Setting the datasource for a Report at runtime
This is one of the most common questions on the ReportViewer Forum. So rather than answer it repeatedly, I will answer it here.
The Basic Idea
The basic idea is to tell your report what type of data it should expect to receive, then at runtime, provide the report with this data before displaying it. All in all it's actually pretty simple. A common stumbling point is to use the wizards or designer to setup the data, which makes some assumptions that don't work for this scenario.
Prepare the Report
Before you can effectively design your report, you need to set up the data for it. You're not providing an actual data source, instead informing the report what type of data it should expect: the data types, field names, etc. The easiest way to do this is to add a DataSet to your project. Right click on your project in the solution explorer and add a new item. Select to add a DataSet, your project should be updated with an .xsd file and you should find it opened in the DataSet designer (as the image below shows.) Once added, use the DataSet designer to design what the schema of your data looks like.
This DataSet needs to exactly match your actual data, schema-wise.
Now, add this DataSet as a DataSource for your report. In the report, go to the Report menu, select DataSources, and add the DataSet
With the DataSet added, it is now available in the Data Sources palette, and you can drag fields into your report in order to design it. Once your report is designed the way you like, you need to add it to your ReportViewer in your form.
Specifying the Report in the ReportViewer
This part is crucial. You must specify the report to be used via the PropertyGrid, not the smart tags on the ReportViewer. If you use the smart tags, it acts somewhat "wizard" like and will do more for you than you want, it will add code in the Designer file to setup the DataSet you added as the datasource at runtime too. You don't want that, that DataSet was just to design the schema of the data; at runtime it would be empty and useless. If you use the PropertyGrid instead, none of these extra operations will take place.
Hooking up the DataSource at Runtime
Finally, you need to let the ReportViewer know where to get the actual data from so it can feed that into the report. In your form's OnLoad method (or wherever is appropriate for your application), you need to add code much like this:
private void Form1_Load(object sender, EventArgs e) {
// somehow get the data at runtime, application specific
this.myData = GetDataSource();
this.reportViewer1.LocalReport.DataSources.Add(new ReportDataSource("DataSet_Person", myData));
this.reportViewer1.RefreshReport();
}
Notice we are adding a DataSource to the ReportViewer. This is the bridge from your data into the report. Key here is the name you specify for the ReportDataSource, it must match the name found in the .rdlc file for this dataset. This name was determined by how you named the DataSet you added to your project and designed. If you view the .rdlc file in the XML editor (right click it and select "Open With..." then pick "XML Editor"), you will find a <DataSets> node, containing a <DataSet> node, this node is the report's understanding of the data for this report, and what your actual data will map to at runtime. Notice the Name attribute of the DataSet node, this is the name you need to specify in the ReportDataSource constructor.
<DataSets>
<DataSet Name="DataSet1_Person">
<Fields>
<Field Name="id">
<DataField>id</DataField>
<rd:TypeName>System.Int32</rd:TypeName>
</Field>
<Field Name="Name">
As your application runs you may wish to switch that data source to something else. Just clear out the ReportDataSource collection, and perform the above steps again.
Updating the DataSource
Later on in your development you might realize your data needs a different schema. This is easy to fix. Go back into the DataSet designer, make the changes needed and save the DataSet. Then, return to the report, go into the Report menu, select DataSources... then select "Refresh All". Click "OK", then save the report. Your report has been updated.
Conclusion
That's all there is to it. Obviously my example is quite a bit more simple than a real application, but the concept is the same. If you have more than one data source, then just repeat the above process once for each data source, and at runtime, add one ReportDataSource for each of your data sources. You can skip the dummy DataSet process altogether and design your schema directly in the .rdlc file, but using the DataSet designer is much easier, not to mention any future changes you make are easy to update in the report.
Comments
Anonymous
September 15, 2010
Thanx a lot, U make my day, this approach is much easier than making CLASS for very table.Anonymous
May 24, 2011
I hade to try this way on vb2010 reportviewer try to load ,but not workAnonymous
January 29, 2012
Hey Reno, try to put code in IsPostback blockAnonymous
March 22, 2012
Question: can I delete the .xsd file now?Anonymous
September 13, 2012
I love this article, took all day to find then remembered this is how you do it. Post above yes you can delete the xsd but I would keep it if you need to make future changes.Anonymous
November 19, 2012
Do u have to specify the report in the property table of the report viewer? I want to change the report at runtime, will it work too?Anonymous
May 27, 2013
Saved my life! Thank you so muchAnonymous
June 11, 2013
Is it possible to use child collections of the data you pass? Eg Order -> OrderItem How would you set the dataset up then ? Thanks in advanceAnonymous
August 12, 2013
Does not work. Always get "A data source instance has not been supplied for the data source 'DataSet1'. "Anonymous
February 21, 2014
This worked like a charm with 2008, but with 2012 the Fields collection is not being populated.Anonymous
August 10, 2014
Can i have the source code of this sample project?Anonymous
January 20, 2015
Thanks very much! It is very helpful.