1
votes

Following on from an earlier question about dynamic columns in a report viewer, I thought I would at least attempt to get things working.
The output being displayed are columns of mathematical factors, each with their own unique name. These factors (any number from 1 to 10 can be selected) display without issue in my DataGridView control - I generate a DataTable by adding rows/columns as required, and then set the datatable as the Datasource for the DataGridView.
I have added a ReportViewer to my WinForm, and generated a RDLC file. Rather than spend hours trying to figure out how to make it dynamic, my RDLC is set up with 10 columns (as I know there will never be more than this), and the DataSet is assigned to my ReportViewer control. I then use the following code to assign the data to the viewer:

DataTable dt = new DataTable();
var source = this.dgvSelectedElements.DataSource;
while (source is BindingSource)
{
    source = ((BindingSource)source).DataSource;
}
var table = source as DataTable;
if (table != null)
{
    dt = table;
    var reportSource = new ReportDataSource("FactorReport", dt);
    this.reportViewer1.Reset();
    this.reportViewer1.ProcessingMode = ProcessingMode.Local;            
    this.reportViewer1.LocalReport.ReportPath = "FactorReport.rdlc";
    this.reportViewer1.LocalReport.DataSources.Clear();
    this.reportViewer1.LocalReport.DataSources.Add(reportSource);
    this.reportViewer1.RefreshReport();
}

So this is how the DataGridview looks:
enter image description here And then, this is the Reportviewer - note the two 'Rate' and 'Mult' rows appear at the bottom enter image description here enter image description here
So whilst it appears to work, I cannot see the values in the grid. Also, when the ages exceed 100, the ages are sorted incorrectly - can sorting be turned off? And on the assumption I can get this to work, is it possible to iterate through the ReportViewer and amend the column captions? A quick google tells me not at run-time?

2

2 Answers

1
votes

You should set name of columns in your DataTable which you ceate dynamically as DataSource of DataGridView correctly. They should be Age, Factor1, Factor2, ... , Factor10.

You created the report using those column names. So when you create a DataTable for your grid dynamically, you should set column names same as names you used when creating report.

How can I have same column names?

But you can fix the problem simply by creating a temporary DataTable containing Age, Factor1, ... , Factor10, filled by the original data table. Pass this table to the report and it will work.

How can I have same column titles which is shown in DataGridView?

The solution is column titles as parameters. Create 10 parameters in the report designer and set the title of columns of tablix in report using parameters but don't change name of columns. Those should be Age, Factor1, .... Then when you want to show the report, additional to the temp table which I mentioned above, pass column titles using parameters.

Another Idea

As another idea, you can have the report using exactly the same DataTable which contains all available columns and then when you want to show some columns in report, just pass some parameters to grid which indicates visibility of each column.

1
votes

Maybe not the best/quickest solution but it works and with some additional changes to the visibility expressions, I'm able to only show the number of columns that have been selected.
I added 10 parameters to my reportviewer named Factor_Name_1 to Factor_Name_10, and checked 'Allow null value' in the properties when creating them. I then wrote some code to add the data for the parameters, storing the existing column names before renaming them to my Factor1, Factor2...Factor10 headings as follows (note I am not worried about in the first 'Age' column):

        // loop through the columns to create parameters...
        for (int i = 1; i < dt.Columns.Count; i++)
        {
            // get the name of the column...
            string factorName = dt.Columns[i].ColumnName;
            // define the new column name...
            string colName = string.Format("Factor_Name_{0}", i);
            // change the column name now we have stored the real name...
            dt.Columns[i].ColumnName = string.Format("Factor{0}", i);
            // generate the parameter...
            var rparam = new ReportParameter(colName, factorName);
            // add it to the parameter set for the control...
            this.reportViewer1.LocalReport.SetParameters(new[] { rparam });
        }

By re-setting the column names once I've created the associated parameter, the data will then bind correctly. All I had to do then, in my RDLC designer, is to replace the existing headings with the associated parameter values. Then, to hide the columns not selected, I set the visibility expression for the Parameter and Row Textboxes to:

=IIF(ISNOTHING(Parameters!Factor_Name_1.Value),True,False)
....
....
=IIF(ISNOTHING(Parameters!Factor_Name_10.Value),True,False)

Now, if I choose 1 or 10 columns, the viewer displays the correct number of columns and hides those not required. Am now working on repeating the 'age' column (already have the headings repeating) and adding a header/footer at runtime, but I currently have a report that displays the data I need with the correct headings.
With four items selected
With ten items selected Thanks to @Reza Aghaei for getting me on the right track.