You may come across a requirement where you need to create a grid with dynamic columns. In such a case our model is may not fixed, it is getting change at runtime, in other words you can say it’s dynamic. In such cases it’s really a headache to bind such data to a single grid. This can be achieved by binding DataTable to the grid.
Here is how we can achieve this.
1. First, we have to get all our data in one DataTable.
a. We can convert list into DataTable, one can use below method to convert list into DataTable
public static DataTable ConvertListToDataTable<T>(List<T> items)
{
DataTable dataTable = new DataTable(typeof(T).Name);
//Get
all the properties
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo prop in Props)
{
//Setting
column names as Property names
dataTable.Columns.Add(prop.Name);
}
//Fill
data into DataTable
foreach (var item in items)
{
var values = new object[Props.Length];
for (int i = 0; i < Props.Length; i++)
{
//inserting property values to datatable rows
values[i] =
Props[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
//put a
breakpoint here and check datatable
return dataTable;
}
(OR)
private DataTable GetDataTable()
{
var connection = ConfigurationManager.ConnectionStrings["ConnectionStringName"].ConnectionString;
using (var dataAdapter = new SqlDataAdapter("SELECT * from
TableName", connection))
{
var dataTable = new DataTable();
dataAdapter.Fill(dataTable);
dataAdapter.FillSchema(dataTable, SchemaType.Mapped);
return dataTable;
}
}
2. Then write a method to read data for grid, this method will be called when data requested.
public ActionResult Read([DataSourceRequest] DataSourceRequest
request)
{
DataTable Data = GetDataTable();
return Json(products.ToDataSourceResult(request));
}
3. And at the end we need to create telerik mvc grid in our view, code snippet is as follows:-
@model
System.Data.DataTable
@(Html.Kendo().Grid<dynamic>()
.Name("gridDataView")
.Columns(columns =>
{
foreach (System.Data.DataColumn column in Model.Columns)
{
//You can write additional validation on columns if needed,
as shown
if (column.DataType.FullName ==
"System.DateTime")
{
var c =
columns.Bound(column.ColumnName).Format("{0:MM/dd/yyyy}");
}
else
{
var c =
columns.Bound(column.ColumnName);
}
//Can have footar Template
if (column.ColumnName == "UnitPrice")
{
c.ClientFooterTemplate("sum:#:sum#").ClientGroupFooterTemplate("sum:#:sum#");
}
}
//Can Have EDIT/DELETE/UPDATE buttons
//columns.Command(cmd=>cmd.Edit());
})
.Pageable()
.Sortable()
//.Editable(ed=>ed.Mode(GridEditMode.PopUp))
.Editable(editable => editable.Mode(GridEditMode.InLine))
.Filterable()
.Groupable()
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
var id =
Model.PrimaryKey[0].ColumnName;
model.Id(id);
foreach (System.Data.DataColumn column in Model.Columns)
{
var field =
model.Field(column.ColumnName, column.DataType);
if
(column.ColumnName == id)
{
field.Editable(false);
}
}
})
.Aggregates(a=>
{
a.Add("UnitPrice", typeof(decimal?)).Sum();
})
.Read(read => read.Action("Read", "Home"))
//.Update(update => update.Action("Update",
"Home"))
)
)
We are done!
I was trying to implement this but getting nullreferancr exception "System.NullReferenceException: Object reference not set to an instance of an object.". Any idea?
ReplyDeleteThis should work, looks like you are declaring some object but not creating it's instance.
DeleteMangal Help Plz.I am using the telerik extension grid.
ReplyDeleteMy code is :
@(Html.Telerik().Grid(Model.CustomReportData.Tables[0])
.Name("CustomReportRunGrid")
.Groupable(grouping => grouping
.Groups(groups =>
{
foreach (var item in (IList)ViewBag.GroupBy)
{
groups.Add(item.GroupOn, typeof(string));
}
}))
.ClientEvents(events => events.OnDataBinding("onDataBinding"))
.Columns(columns =>
{
foreach (DataColumn column in Model.CustomReportData.Tables[0].Columns)
{
var GroupByList = (IList)ViewBag.GroupBy;
bool ContainsItem = (GroupByList).Any(Col => Col.FieldName == column.ColumnName);
if (ContainsItem)
{
IList item = (GroupByList).Where(col => col.FieldName == column.ColumnName).Select(col => col).ToList();
if (item[0].Condition.ToString() == "MAX")
{
if (column.DataType.Name == "DateTime")
{
columns.Bound(column.DataType, column.ColumnName).Aggregate(a => a.Max()).GroupFooterTemplate(result => "Max : " + result.Max.Format("{0:MM/dd/yyyy}")).Format("{0:MM/dd/yyyy}").ClientGroupFooterTemplate("Max : <#= Max #>").Format("{0:MM/dd/yyyy}");
}
else
{
columns.Bound(column.DataType, column.ColumnName).Aggregate(a => a.Max()).GroupFooterTemplate(result => "Max : " + result.Max).ClientGroupFooterTemplate("Max : <#= Max #>");
}
}
else if (item[0].Condition.ToString() == "MIN")
{
if (column.DataType.Name == "DateTime")
{ columns.Bound(column.DataType, column.ColumnName).Aggregate(a => a.Min()).GroupFooterTemplate(result => "Min : " + result.Min.Format("{0:MM/dd/yyyy}")).Format("{0:MM/dd/yyyy}").ClientGroupFooterTemplate("Min : <#= Min #>").Format("{0:MM/dd/yyyy}"); }
else { columns.Bound(column.DataType, column.ColumnName).Aggregate(a => a.Min()).GroupFooterTemplate(result => "Min : " + result.Min).ClientGroupFooterTemplate("Min : <#= Min #>"); }
}
}
}
})
.DataBinding(dataBinding =>
{
dataBinding.Ajax().OperationMode(GridOperationMode.Client)
.Select("CustomReportRunAction", "Report");
})
.Pageable(settings => settings.PageSize(gridPageSize).Position(GridPagerPosition.Both))
.Sortable()
)
It works well in every scenario. Except the max min aggregate on dates.
When I apply max or min or dates , it gives me zero on group footer.
I think Aggregate function should not be declared this way.
DeleteCheck this link:- http://www.telerik.com/forums/datatable-aggregete-functions
(Also check sample project link available there.)
Mangal I am not using Kendo. I am using telerik extension grid. And telerik extension doesn't support any aggregate function on grid level. It need to declared with columns.
ReplyDeleteAnd also only max & min are not working for dates. It's works for count date or Max min numbers.
ok..I will check.
DeleteHi Mangalsingh,
ReplyDeletearticle is good. is it possible to have sample application for download
Thanks Ganesh.
DeleteYes,you can download sample application from below link,
Sample Application
Kendo ui not showing records if record count is more than 50000?
ReplyDelete