Search code examples
c#asp.net-mvctelerik-reporting

tekerik report mvc dynamic columns


There is problem with dynamic creation of table columns in MVC Report. Situation is in the following.

In my Report.cs file I override OnNeedDataSource() method. In it I create System.Data.DataTable, then attach this DataTable to Telerik's table as DataSource.

Code for this methods:

/// <summary>
/// Creates DataTable from ReportRecords
/// </summary>
/// <param name="data">List of ReportRecords</param>
/// <returns>DataTable filled with ReportRecord's values</returns>
private System.Data.DataTable CreateDataTable(List<ReportRecord> data)
{
    System.Data.DataColumn currentColumn = new System.Data.DataColumn("Current", typeof(int));
    System.Data.DataColumn lateColumn = new System.Data.DataColumn("Late", typeof(int));
    System.Data.DataColumn foreignColumn = new System.Data.DataColumn("Foreign", typeof(int));

    System.Data.DataTable table = new System.Data.DataTable("table");
    table.Columns.AddRange(new System.Data.DataColumn[] { currentColumn, lateColumn, foreignColumn });

    foreach (ReportRecord reportRecord in data)
    {
        System.Data.DataRow row = table.NewRow();

        row["Current"] = reportRecord.Current;
        row["Late"] = reportRecord.Late;
        row["Foreign"] = reportRecord.Foreign;

        table.Rows.Add(row);
    }

    return table;
}



/// <summary>
/// Assign DataTable as DataSource of dinamically created table in report
/// </summary>
/// <param name="table">DataTable with data to display</param>
private void AddTableToReport(System.Data.DataTable table)
{
    this.tableMain.DataSource = table;

    //create two HtmlTextBox items (one for header and one for data) which would be added to the items collection of the table
    Telerik.Reporting.TextBox textboxGroup;
    Telerik.Reporting.TextBox textBoxTable;

    //we do not clear the Rows collection, since we have a details row group and need to create columns only
    this.tableMain.ColumnGroups.Clear();
    this.tableMain.Body.Columns.Clear();
    this.tableMain.Body.Rows.Clear();
    int i = 0;
    this.tableMain.ColumnHeadersPrintOnEveryPage = true;
    foreach (System.Data.DataColumn dc in table.Columns)
    {
        Telerik.Reporting.TableGroup tableGroup = new Telerik.Reporting.TableGroup();
        Telerik.Reporting.TableGroup tableGroup2 = new Telerik.Reporting.TableGroup();
        tableGroup.ChildGroups.Add(tableGroup2);
        this.tableMain.ColumnGroups.Add(tableGroup);
        this.tableMain.Body.Columns.Add(new Telerik.Reporting.TableBodyColumn(Unit.Inch(1)));

        textboxGroup = new Telerik.Reporting.TextBox();
        textboxGroup.Style.BorderColor.Default = Color.Black;
        textboxGroup.Style.BorderStyle.Default = BorderType.Solid;
        textboxGroup.Value = dc.ColumnName;
        textboxGroup.Size = new SizeU(Unit.Inch(1.1), Unit.Inch(0.3));
        tableGroup.ReportItem = textboxGroup;

        textBoxTable = new Telerik.Reporting.TextBox();
        textBoxTable.Style.BorderColor.Default = Color.Black;
        textBoxTable.Style.BorderStyle.Default = BorderType.Solid;
        textBoxTable.Value = "=Fields." + dc.ColumnName;
        textBoxTable.Size = new SizeU(Unit.Inch(1.1), Unit.Inch(0.3));
        this.tableMain.Body.SetCellContent(0, i++, textBoxTable);

        this.tableMain.Items.AddRange(new ReportItemBase[] { textBoxTable, textboxGroup });  
    }
}

But, as result, I achieve values from first colum of my DataTable in every column of my Telerik's table:

Current   Late    Foreign
0         0        0
20        20       20
1         1        1
21        21       21
4         4        4

But values should be the following:

Current  Late    Foreign
0        0        1
20       1        0
1        0        6
21       0        0
4        1        0

Why this happens and how to solve the situation?

Also this: Telerik report showing same data for all columns created dynamically does not works for me.


Solution

  • Topic at Telerik's forum: http://www.telerik.com/forums/mvc-dynamic-columns

    Summarizing in short: they changed something in newer versions of Telerik so that you can not modify reports in event handlers such as OnNeedDataSource or ItemDataBinding:

    Report Events are not intended to be used as a place/time to modify the report definition. As of Q3 2016 any changes on the report items' definitions in processing stage events will not make effective change in the resulting report. Report definition properties are read and cached when the report processing gets started. In previous versions changes may take effect, resulting in changed output for all processing items processed after the event handler execution.

    Telerik's support suggest two options:

    1. Provide custom ReportResolver
    2. Something like a hack which consist in generating DataSource with some specific markup.

    First solution, in my opinion, is too much complex for such a simple thing as adding columns at runtime. Second solution is a bit ugly.

    I solve this situation in third way: create DataTable and Telerik's table with all possible columns, then fill with data only necessary columns in DataTable, and then hide unnecessary columns in Tekerik's table as described here: http://www.telerik.com/forums/need-to-hide-table-column-that-has-no-data