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.