This is a migrated thread and some comments may be shown as answers.

MVC dynamic columns

8 Answers 706 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Андрей
Top achievements
Rank 1
Андрей asked on 09 Jun 2017, 01:35 PM

Hello.

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?

8 Answers, 1 is accepted

Sort by
0
Андрей
Top achievements
Rank 1
answered on 09 Jun 2017, 01:51 PM
Also this: https://stackoverflow.com/questions/24693147/telerik-report-showing-same-data-for-all-columns-created-dynamically do not works for me.
0
Андрей
Top achievements
Rank 1
answered on 12 Jun 2017, 11:36 AM
Hi there!
Any suggestions how to perform dynamic columns?
0
Андрей
Top achievements
Rank 1
answered on 13 Jun 2017, 08:22 AM

Ask this question at StackOverflow:

https://stackoverflow.com/questions/44515564/tekerik-report-mvc-dynamic-columns

If anyone can help, please help.

0
Stef
Telerik team
answered on 13 Jun 2017, 12:30 PM
Hello Андрей,

It is recommended to serialize the report instance in a TRDX file and to preview it in the Standalone Report Designer. This will let you check if settings are applied correctly for building Reporting items at run-time. you can also design reports with the VS Report Designer in order to reuse the code from the report's Designer.cs file - Modifying or Creating a report at Run-Time.

Below you can find sample code for generating a Table item at run-time that can be used for comparison:
//business object
    public class MyDataObject
    {
        public string Description { get; set; }
        public int ID { get; set; }
        public string Name { get; set; }
    }
 
//data access layer
 public class DataAccessLayer
    {
        public List<MyDataObject> GetData(int total)
        {
            var list = new List<MyDataObject>();
            for (int i = 0; i < total; i++)
            {
                list.Add(new MyDataObject { ID = i, Name = "name" + i.ToString(), Description = "randome text for content" });
            }
            return list;
        }
 
        public List<System.Reflection.PropertyInfo> GetDataSchema()
        {
            return typeof(MyDataObject).GetProperties().ToList();
        }
    }
 
//generate the report at run-time
public ReportSource ModifyReport()
{
                var reportInstance = new Report1();
                //generate content
                var table = CreateTable(receivedClientValues[1]);
                (reportInstance.Items.Find("detail", true)[0] as Telerik.Reporting.DetailSection).Items.Add(table);
                //display the custom report via InstanceReportSource
                IRS.ReportDocument = reportInstance;
 
Telerik.Reporting.Table CreateTable(string headertext)
        {
            //create a blank Table item
            Telerik.Reporting.Table table1 = new Telerik.Reporting.Table();
            table1.Location = new Telerik.Reporting.Drawing.PointU(Telerik.Reporting.Drawing.Unit.Inch(0.0), Telerik.Reporting.Drawing.Unit.Inch(0.0));
            table1.Name = "Table1";
            table1.Size = new Telerik.Reporting.Drawing.SizeU(Telerik.Reporting.Drawing.Unit.Inch(4), Telerik.Reporting.Drawing.Unit.Inch(1));
 
 
            //configure a data source, instead of initializing data objects, as the Resolve method used frequently
            //the ObjectDataSource uses System.Reflection to create an object of the specified type and top execute the selected method
            //method arguments can be mapped to report parameters
            var ODS = new ObjectDataSource() { Name = "ODS1" };
            ODS.DataSource = typeof(DataAccessMethods.DataAccessLayer);
            ODS.DataMember = "GetData";
            ODS.Parameters.Add("total", typeof(int), "=Parameters.Parameter1.Value");
 
            table1.DataSource = ODS;
 
            //create a dynamic row group
            Telerik.Reporting.TableGroup DetailRowGroup = new Telerik.Reporting.TableGroup();
            DetailRowGroup.Groupings.Add(new Telerik.Reporting.Grouping(null));
            DetailRowGroup.Name = "DetailRowGroup";
            table1.RowGroups.Add(DetailRowGroup);
            //add a row container
            table1.Body.Rows.Add(new Telerik.Reporting.TableBodyRow(Telerik.Reporting.Drawing.Unit.Inch(0.5)));
 
            /////////////////////////////
            //we need the data schema in order to design the template at run-time
            var columns = (new DataAccessMethods.DataAccessLayer()).GetDataSchema();
 
            //add columns          
            for (int i = 0; i <= columns.Count - 1; i++)
            {
                //add a column container
                table1.Body.Columns.Add(new Telerik.Reporting.TableBodyColumn(Telerik.Reporting.Drawing.Unit.Inch(2)));
                //add a static column group per data field
                Telerik.Reporting.TableGroup columnGroup = new Telerik.Reporting.TableGroup();
                table1.ColumnGroups.Add(columnGroup);
 
                //header textbox
                Telerik.Reporting.TextBox headerTextBox = new Telerik.Reporting.TextBox();
                headerTextBox.Name = "headerTextBox" + i.ToString();
                headerTextBox.Size = new Telerik.Reporting.Drawing.SizeU(Telerik.Reporting.Drawing.Unit.Inch(2), Telerik.Reporting.Drawing.Unit.Inch(0.5));
                headerTextBox.Value = headertext + columns[i].Name;
                headerTextBox.Style.BackgroundColor = Color.Yellow;
                headerTextBox.Style.BorderStyle.Default = Telerik.Reporting.Drawing.BorderType.Solid;
                //  headerTextBox.Style.BorderWidth.Default = Telerik.Reporting.Drawing.Unit.Pixel(1);
                columnGroup.ReportItem = headerTextBox;
 
                //field that will be displayed
                Telerik.Reporting.TextBox detailRowTextBox = new Telerik.Reporting.TextBox();
                detailRowTextBox.Name = "detailRowTextBox" + i.ToString();
                detailRowTextBox.Size = new Telerik.Reporting.Drawing.SizeU(Telerik.Reporting.Drawing.Unit.Inch(2), Telerik.Reporting.Drawing.Unit.Inch(0.5));
                detailRowTextBox.Value = "= Fields.[" + columns[i].Name + "]";
                table1.Body.SetCellContent(0, i, detailRowTextBox);
 
                //add the nested items in the Table.Items collection
                table1.Items.AddRange(new Telerik.Reporting.ReportItemBase[] {
            headerTextBox,
            detailRowTextBox
        });
 
            }
            return table1;
        }


In future, please use the support ticketing system in case of an emergency. We cannot guarantee a response in public forums by Telerik representatives in a timely manner.
Thank you for your understanding.

Regards,
Stef
Progress Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Андрей
Top achievements
Rank 1
answered on 13 Jun 2017, 01:13 PM
So, the only way to add columns dynamically to table in report is to implement Custom Report Resolver?
0
Stef
Telerik team
answered on 13 Jun 2017, 03:05 PM
Hello,

The previously provided code can be used in a custom resolver plugged in the Reporting REST Service's configuration.

An approach without custom settings of the Reporting REST Service will include loading data in a specific data structure - How to Create a Dynamic Table/Crosstab/List item.

Regards,
Stef
Progress Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Андрей
Top achievements
Rank 1
answered on 13 Jun 2017, 04:11 PM

In my opinion, this is too complex solutions for such simple thing as adding columns dynamically. I hope that Telerik's developers will find a way to modify reports in event handlers such as OnNeedDataSource.

In my certain situation I found the next solution:

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

0
Stef
Telerik team
answered on 14 Jun 2017, 02:38 PM
Hi Andrey,

reports are static templates that distinguish them from grid controls. The report structure can develop dynamically, if you provide groupings that generate the elements in the report when data is processed.

The found workaround is valid. You can retrieve data in the same data structure, assuring the fields used by the report are available in the data schema. Then you can hide fields not displaying anything through the expression engine e.g. the attached video that can be previewed in IE browser.

Regards,
Stef
Progress Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Tags
General Discussions
Asked by
Андрей
Top achievements
Rank 1
Answers by
Андрей
Top achievements
Rank 1
Stef
Telerik team
Share this question
or