I did find some information, but that was on other forums.
Now we have DynamicObject (or ExpandoObject, that's an implementation of DynamicObject as I understood) we, of course, want it to bind to a RadGrid. There is no thread or blog I can find on this issue. It's also a bit of a Sunday afternoon thing for now.
I was wondering what Telerik thinks of this usage, what would be your approach..
And also this tread can grow to be of use to others, that's the main gaol..
We have a dynamic class:
Imports System.IO Imports System.Dynamic Public Class DynamicDictionary Inherits DynamicObject ' The inner dictionary. Dim mdic_PropertyHolder As New Dictionary(Of String, Object) ' This property returns the number of elements in the inner dictionary. ReadOnly Property Count As Integer Get Return mdic_PropertyHolder.Count End Get End Property ReadOnly Property Items As Dictionary(Of String, Object) Get Return mdic_PropertyHolder End Get End Property Public Function GetMembers() As String() Return mdic_PropertyHolder.Keys.ToArray End Function Public Property Item(ByVal PropertyName As String) As String Get Return mdic_PropertyHolder(PropertyName) End Get Set(ByVal value As String) mdic_PropertyHolder(PropertyName) = value End Set End Property ' If you try to get a value of a property that is not defined in the class, this method is called. Public Overrides Function TryGetMember(ByVal binder As System.Dynamic.GetMemberBinder, ByRef result As Object) As Boolean ' Converting the property name to lowercase ' so that property names become case-insensitive. Dim name As String = binder.Name.ToLower() ' If the property name is found in a dictionary, set the result parameter to the property value and return true. Otherwise, return false. Return mdic_PropertyHolder.TryGetValue(name, result) End Function Public Overrides Function TrySetMember(ByVal binder As System.Dynamic.SetMemberBinder, ByVal value As Object) As Boolean ' Converting the property name to lowercase so that property names become case-insensitive. mdic_PropertyHolder(binder.Name.ToLower()) = value ' You can always add a value to a dictionary, so this method always returns true. Return True End Function End ClassIn a asp.net page we have:
<telerik:RadGrid ID="RadGrid1" runat="server" AllowPaging="True" GridLines="None" Width="100%" ShowGroupPanel="True" AllowSorting="True" ShowStatusBar="true"> <MasterTableView RetrieveAllDataFields="true" AutoGenerateColumns="false"> <Columns> <telerik:GridTemplateColumn HeaderText="Hopa" > <ItemTemplate> <span style="white-space:nowrap"><%# Container.DataItem.firstname%></span> </ItemTemplate> </telerik:GridTemplateColumn> <telerik:GridBoundColumn HeaderText="FirstName" DataField="FirstName"> </telerik:GridBoundColumn> <telerik:GridBoundColumn HeaderText="MiddleName" DataField="MiddleName"> </telerik:GridBoundColumn> <telerik:GridBoundColumn DataField="LastName" HeaderText="LastName"> </telerik:GridBoundColumn> </Columns> </MasterTableView> </telerik:RadGrid> In a asp.net page code we have:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Dim person As Object Dim List As New ArrayList ' Adding new dynamic properties. ' The TrySetMember method is called. person = New DynamicDictionary() person.FirstName = "Ellen" person.LastName = "Adams" List.Add(person)
person = New DynamicDictionary() person.FirstName = "Piet" person.LastName = "Pietersen" List.Add(person) person = New DynamicDictionary() person.FirstName = "Erik" person.MiddleName = "van der" person.LastName = "Heide" List.Add(person) person = New DynamicDictionary() person.FirstName = "Jan" person.LastName = "Janssen" List.Add(person) RadGrid1.DataSource = List RadGrid1.DataBind() End SubPrivate Sub RadGrid1_ItemDataBound(sender As Object, e As Telerik.Web.UI.GridItemEventArgs) Handles RadGrid1.ItemDataBound If TypeOf e.Item Is GridDataItem Then Dim dataBoundItem As GridDataItem = e.Item For Each Member As String In dataBoundItem.DataItem.GetMembers Try dataBoundItem(Member).Text = dataBoundItem.DataItem.Item(Member) Catch ex As Exception ' Oops End Try Next End IfEnd SubThis is of course not verry fast, but verry flexible it is. Editing is an issue I think, but displaying is not.
Regards,
Erik
15 Answers, 1 is accepted
This approach can be very useful. Thank you for sharing it with the whole community.
It is a nice way of using the dynamic object that is supported in .Net 4.0
Here is C# version of the code that also supports editing.
ASPX:
<telerik:RadGrid ID="RadGrid1" runat="server" OnNeedDataSource="RadGrid1_NeedDataSource" AutoGenerateEditColumn="true" AutoGenerateColumns="false" AllowAutomaticUpdates="false" OnUpdateCommand="RadGrid1_UpdateCommand"> <MasterTableView> <Columns> <telerik:GridTemplateColumn HeaderText="First name"> <ItemTemplate> <%# (Container.DataItem as dynamic).FirstName%> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" ID="FirstNameTextbox" Text=" <%# (Container.DataItem as dynamic).FirstName%> "> </asp:TextBox> </EditItemTemplate> </telerik:GridTemplateColumn> </Columns> </MasterTableView></telerik:RadGrid>C#:
using System.Dynamic;using Telerik.Web.UI;public partial class RadGridBindingToListOfDynamicDict : System.Web.UI.Page{ public class DynamicDictionary : DynamicObject { Dictionary<string, object> dictionary = new Dictionary<string, object>(); public int Count { get { return dictionary.Count; } } public override bool TryGetMember(GetMemberBinder binder, out object result) { string name = binder.Name.ToLower(); return dictionary.TryGetValue(name, out result); } public override bool TrySetMember(SetMemberBinder binder, object value) { dictionary[binder.Name.ToLower()] = value; return true; } } protected List<dynamic> LoadData() { List<dynamic> data = new List<dynamic>(); dynamic person; person = new DynamicDictionary(); person.FirstName = "Ellen"; person.LastName = "Adams"; data.Add(person); person = new DynamicDictionary(); person.FirstName = "Piet"; person.LastName = "Pietersen"; data.Add(person); person = new DynamicDictionary(); person.FirstName = "Erik"; person.MiddleName = "van der"; person.LastName = "Heide"; data.Add(person); person = new DynamicDictionary(); person.FirstName = "Jan"; person.LastName = "Janssen"; data.Add(person); return data; } protected void Page_Load(object sender, EventArgs e) { if (Session["data"] == null) { Session["data"] = LoadData(); } } protected void RadGrid1_NeedDataSource(object sender, Telerik.Web.UI.GridNeedDataSourceEventArgs e) { (sender as RadGrid).DataSource = (List<dynamic>)Session["data"]; } protected void RadGrid1_UpdateCommand(object source, GridCommandEventArgs e) { string newFirstName = (e.Item.FindControl("FirstNameTextbox") as TextBox).Text; ((List<dynamic>)Session["data"])[e.Item.DataSetIndex].FirstName = newFirstName; }}Kind regards,
Vasil
the Telerik team
Browse the vast support resources we have to jump start your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
I used the above example which works fine but I have problems grouping.
When I try to group by one of the columns I get the following Server exception:
at Telerik.Web.UI.GridDataSetHelper.CreateGroupByTable(DataTable SourceTable, GridTableView view)at Telerik.Web.UI.GridDataSetHelper.CalcGroupByTables(GridTableView gridTableView, DataTable SourceTable, String RowFilter, Int32 FirstIndex, Int32 LastIndex, Boolean applyPaging, Boolean isCustomPaging)at Telerik.Web.UI.GridEnumerableFromDataView.PerformTransformation()at Telerik.Web.UI.GridEnumerableFromDataView.TransformEnumerable()at Telerik.Web.UI.GridTableView.GetEnumerator(Boolean useDataSource, GridEnumerableBase resolvedDataSource, ArrayList dataKeysArray)at Telerik.Web.UI.GridTableView.CreateControlHierarchy(Boolean useDataSource)at Telerik.Web.UI.GridTableView.CreateChildControls(IEnumerable dataSource, Boolean useDataSource)at System.Web.UI.WebControls.CompositeDataBoundControl.PerformDataBinding(IEnumerable data)at System.Web.UI.WebControls.DataBoundControl.OnDataSourceViewSelectCallback(IEnumerable data)at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback)at System.Web.UI.WebControls.DataBoundControl.PerformSelect()at Telerik.Web.UI.GridTableView.PerformSelect()at System.Web.UI.WebControls.BaseDataBoundControl.DataBind()at Telerik.Web.UI.GridTableView.DataBind()at Telerik.Web.UI.GridTableView.BindAllInHierarchyLevel()at Telerik.Web.UI.RadGrid.RaisePostBackEvent(String eventArgument)at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)or on Client side:
Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerServerErrorException: Field FirstName not found in the source table. Please check the expression syntax.
<telerik:RadGrid ID="RadGrid2" runat="server" PageSize="10" AllowSorting="True" AllowMultiRowSelection="True" AllowPaging="True" AllowCustomPaging="false" ShowGroupPanel="True" AutoGenerateColumns="false" GridLines="none"> <PagerStyle Mode="NextPrevNumericAndAdvanced"></PagerStyle> <ClientSettings ReorderColumnsOnClient="True" AllowDragToGroup="True" AllowColumnsReorder="True"> <Selecting AllowRowSelect="True"></Selecting> <Resizing AllowRowResize="false" AllowColumnResize="True" EnableRealTimeResize="True" ResizeGridOnColumnResize="False"></Resizing> </ClientSettings> <GroupingSettings ShowUnGroupButton="true" /> <MasterTableView Width="100%"> <Columns> <telerik:GridTemplateColumn HeaderText="First name" DataField="LastName" SortExpression="LastName" GroupByExpression="FirstName group by FirstName"> <ItemTemplate> <%# (Container.DataItem as dynamic).FirstName%> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" ID="FirstNameTextbox" Text=" <%# (Container.DataItem as dynamic).FirstName%> "> </asp:TextBox> </EditItemTemplate> </telerik:GridTemplateColumn> <telerik:GridTemplateColumn HeaderText="Last name" DataField="LastName" SortExpression="LastName" GroupByExpression="LastName group by LastName"> <ItemTemplate> <%# (Container.DataItem as dynamic).LastName%> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" ID="LastNameTextbox" Text=" <%# (Container.DataItem as dynamic).LastName%> "> </asp:TextBox> </EditItemTemplate> </telerik:GridTemplateColumn> </Columns> </MasterTableView> </telerik:RadGrid>
Unfortunately the RadGrid does not support filtering/sorting/paging when it is bound to collection of . DynamicObjects. RadGrid supports binding to generic collection of .NET 4.0 dynamic type objects. For more information please check out the following online example:
http://demos.telerik.com/aspnet-ajax/grid/examples/programming/dynamictypes/defaultcs.aspx
Regards,
Radoslav
the Telerik team
[=Fields.FirstName]
and
this.textBox.Value = "=(Container.DataItem as dynamic).FirstName";
don't seem to work.
thanks
If you want to bind a control property to the value of object's property boxed into dynamic object by using binding expressions you could try using Eval and bind directly to the property. For example:
<telerik:RadGrid ID="RadGrid1" AllowFilteringByColumn="true" runat="server" AllowPaging="true" PageSize="4" AutoGenerateColumns="true" ShowStatusBar="true" AllowSorting="true" OnNeedDataSource="RadGrid1_NeedDataSource"> <MasterTableView PagerStyle-AlwaysVisible="true"> <Columns> <telerik:GridTemplateColumn DataField="Name"> <ItemTemplate> <asp:TextBox runat="server" ID="TextBox1" Text='<%# DataBinder.Eval(Container.DataItem, "Name") %>'></asp:TextBox> </ItemTemplate> </telerik:GridTemplateColumn> </Columns> </MasterTableView> <ClientSettings EnablePostBackOnRowClick="true"> <Selecting AllowRowSelect="true" /> </ClientSettings> </telerik:RadGrid>protected void RadGrid1_NeedDataSource(object sender, GridNeedDataSourceEventArgs e) { dynamic data = new[] { new { ID = 1, Name ="Name1"}, new { ID = 2, Name = "Name2"}, new { ID = 3, Name = "Name3"}, new { ID = 4, Name = "Name4"}, new { ID = 5, Name = "Name5"}, new { ID = 6, Name ="Name6"}, new { ID = 7, Name = "Name7"}, new { ID = 8, Name = "Name8"}, new { ID = 9, Name = "Name9"}, new { ID = 10, Name = "Name10"}, new { ID = 11, Name ="Name11"}, new { ID = 12, Name = "Name12"}, new { ID = 13, Name = "Name13"}, new { ID = 14, Name = "Name14"}, new { ID = 15, Name = "Name15"} }; RadGrid1.DataSource = data; }I hope this helps.
Kind regards,
Radoslav
the Telerik team
I am using Normal Telerik grid control not Rad one. But can this above dynamic list bind with my telerik normal grid control as well?
Could you please elaborate a bit more on your scenario? What do you mean by “I am using Normal Telerik grid control not Rad one”?
Looking forward for your reply.
Kind regards,
Radoslav
the Telerik team
From last 2 weeks i am running into a problem. I am working with MVC applicaiton where i have to implement Telerik grid with dynamic columns. I have done this by Data Table. This table containing column name as DateTime like "2/3/2013 Sunday" or "7:30 AM" and this is the issue. Telerik grid is not binding data with date and time column name. Though if i change the column name to any string value like "Sunday" or any "Text" value then it is working fine.
Index.cshtml
@using System.Data;@model DataTable@{ ViewBag.Title = "Home Page";}<h2>@ViewBag.Message</h2> @(Html.Telerik().Grid<System.Data.DataRow>(Model.Rows.Cast<System.Data.DataRow>()) .Name("Grid") .Columns(columns => { foreach (System.Data.DataColumn column in Model.Columns) { if(column.ColumnName != "ShopName") columns.Bound(column.DataType, column.ColumnName).Width(50).Sortable(false).Filterable(false); else columns.Bound(column.DataType, column.ColumnName).Width(50).Sortable(true).Filterable(true); } }) .DataBinding(dataBinding => dataBinding.Ajax().Select("_CustomBinding", "Home")) .Pageable() .Sortable() .Filterable() )HomeController.cs
public class HomeController : Controller { private static int count; ShopLoadGridModel model = new ShopLoadGridModel(); public ActionResult Index() { ViewBag.Message = "Welcome to ASP.NET MVC!"; ViewData["total"] = 100; DataTable table = new DataTable(); table = model.DataTableColumnSettings; return View(table); } [GridAction(EnableCustomBinding = true)] public ActionResult _CustomBinding(GridCommand command) { model.ShopLoadGridCommand = command; model.Load(); IEnumerable data = model.ShopLoadGridSummaryIEnumerable; count = 3; GridModel model1 = new GridModel(); return View(new GridModel { Data = data, Total=count }); } }Model Class
Creating column settings with column name
DataTable table = new DataTable(); table.Columns.Add("ShopName", typeof(string)); table.Columns.Add("WIP", typeof(string)); table.Columns.Add("CurrentRO", typeof(string)); table.Columns.Add("Total", typeof(string)); bool continueLoop = true; int limit = 0; while (continueLoop) { //I want column name like from 7:30 AM to 8:30 PM, if below Date and days column name works fine string columnName = DateTime.Now.AddDays(limit).ToShortDateString() +" " + DateTime.Now.AddDays(limit).DayOfWeek; table.Columns.Add(columnName, typeof(string)); if (limit == 7)// No of columns (5 static + 56 dynamic) continueLoop = false; limit++; } return table;Filling data which will display in grid
var serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJSONConverter() }); List<Dictionary<string, string>> data = new List<Dictionary<string, string>>(); bool continueLoop = true; int limit = 0; for (int i = 1; i <= 3; i++) { continueLoop = true; limit = 0; dynamic diarioModel = new ExpandoObject(); var dictionary = (IDictionary<string, string>)diarioModel; dictionary.Add("ShopName", "Shop" + i.ToString()); dictionary.Add("WIP", i.ToString()); dictionary.Add("CurrentRO", i.ToString()); dictionary.Add("Total", i.ToString()); dictionary.Add("Amount", i.ToString()); while (continueLoop) { string columnName = DateTime.Now.AddDays(limit).ToShortDateString() +" " + DateTime.Now.AddDays(limit).DayOfWeek; dictionary.Add(columnName, Convert.ToString(limit + i)); if (limit == 7)// No of columns (5 static + 56 dynamic) continueLoop = false; limit++; } var json = serializer.Serialize(dictionary); var d = serializer.Deserialize<dynamic>(json); data.Add(d); }I have mentioned all the major code here, but if want test project i can share.
For any help will much appreciated.
Thanks,
Jitender
The column field name should be valid for JavaScript and currently the name contains invalid characters. You should remove all invalid characters from the name in order for the data to be bound correctly. If you wish to show the title in a different format then you can use the Title method e.g.
table.Columns.Add(new DataColumn { ColumnName = DateTime.Now.AddDays(limit).DayOfWeek + DateTime.Now.AddDays(limit).ToShortDateString().Replace(" ", "").Replace("/",""), Caption = DateTime.Now.AddDays(limit).ToShortDateString() + " " + DateTime.Now.AddDays(limit).DayOfWeek, DataType = typeof(string) });columns.Bound(column.DataType, column.ColumnName).Title(column.Caption).Width(50).Sortable(true).Filterable(true);Daniel
the Telerik team
Suggestion provided by you surely the one which i wanted. BTW i have resolved this issue by using GridColumnSettings for column setting and datatable for dynamic data using MVC kendo UI grid control.
Thanks again :)
-Jitender
There isn't a way to use DataAnnotation attributes with dynamic objects.
Regards,Daniel
Telerik
I'm trying to use Vasil's example posted 21 April, 2011 but doing it all programmatically, defining the radgrid in codebehind. My grid has 2 set columns plus an 'x' number of added GridTemplateColumns only known at run time. I'm declaring the boundColumns as such
GridBoundColumn boundColumn;
boundColumn = new GridBoundColumn();
boundColumn.UniqueName = "id";
boundColumn.DataField = "id";
boundColumn.DataType = typeof(System.Int32);
boundColumn.HeaderText = "Volunteer #".Translate();
boundColumn.HeaderStyle.Width = Unit.Pixel(70);
boundColumn.Resizable = true;
grid.MasterTableView.Columns.Add(boundColumn);
boundColumn = new GridBoundColumn();
boundColumn.UniqueName = "name";
boundColumn.DataField = "name";
boundColumn.DataType = typeof(System.String);
boundColumn.HeaderText = "Name";
boundColumn.Resizable = true;
boundColumn.HeaderStyle.Width = Unit.Pixel(200);
grid.MasterTableView.Columns.Add(boundColumn);
I populate the Datasource using the same NeedDataSource but when the grid displays the cells are empty.
I noticed that there is no DataKeyNames defined, is that because using DynamicObject? is there an example showing how to build the grid totally backend (assigning to a placeholder) where the grid structure is dynamic such that the number of columns and header info is pulled from the database.
Thanks
Tim
I recommend checking out the Creating a RadGrid Programmatically documentation article which describes several approaches you can use. It is also mentioned, when creating Template Columns programmatically, the entire grid structure must be created in the code behind: Creating Template Columns Programmatically
DataKeyNames are not populated automatically, this also needs to be set by the developer at the same time the ID and other properties are defined. (example in the following code snippet: Dynamically Defining the Structure of a Statically-declared Grid)
RadGrid1.MasterTableView.DataKeyNames = new string[] { "CustomerID" };I hope this will be helpful.
Kind regards,
Attila Antal
Progress Telerik

