In a telerik:RadGrid, I specify that every line will have a detail table:
<telerik:RadGrid ID="grd" AutoGenerateColumns="False" runat="server" OnDetailTableDataBind="grd_OnDetailTableDataBind" AllowMultiRowSelection="True"> <MasterTableView DataKeyNames="id1,id2"> <Columns> <telerik:GridClientSelectColumn UniqueName="DetailCheckColumn"/> <telerik:GridBoundColumn HeaderText="Date" DataField="foo"/> <telerik:GridBoundColumn HeaderText="Time" DataField="bar"/> <telerik:GridBoundColumn HeaderText="Activity" DataField="xod"/> </Columns> <DetailTables> <telerik:GridTableView ShowHeadersWhenNoRecords="True" DataKeyNames="id" Name="Child"/> </DetailTables> </MasterTableView> <ClientSettings> <Selecting AllowRowSelect="true"/> </ClientSettings> </telerik:RadGrid>In the handler for the OnDetailTableDataBind event, I specify the data source for the DetailTableView. The handler is called when a line is expanded. Setting a list of anonymous objects as data source works fine, but a list of Dictionary will not.
I get a yellow page, It seems like the grid table view tries to find a property id of Dictionary
DataBinding: System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] does not have a property with the name id.
If I remove the DataKeyNames attribute in the detail table, I will get a detail table with the correct number of lines, but the fields will be all blank (screenshot is attached).
The event handler where I create the detail table for each expanded line. Observe that I name columns c1, c2 etc. I create the columns in the first loop round.
protected void grd_OnDetailTableDataBind(object sender, GridDetailTableDataBindEventArgs e){ var tv = e.DetailTableView; var parentItem = e.DetailTableView.ParentItem; var bis = dal.get_booking_informations(); tv.Columns.Add(new GridClientSelectColumn()); var columnNameDict = new Dictionary<string,string>(); var firstDict = true; var dicts = bis.GroupBy(bi=>bi.platsBokadID).Select(group => { var dict = new Dictionary<string, string>(); dict["id"] = "" + group.Key; var list = group.ToList(); if (firstDict) { firstDict = false; var num = 0; var columns = list.Select(header=> { var shortName = "c" + ++num; columnNameDict[header.HeaderName] = shortName; return new GridBoundColumn { DataField = shortName, HeaderText = header.HeaderName }; }); foreach(var column in columns) tv.Columns.Add(column); } foreach(var header in list) { var shortName = columnNameDict[header.HeaderName]; dict[shortName] = header.Value; } return dict; }); tv.DataSource = dicts;}I have also tried to use dynamic objects instead of Dictionaries (with the same result):
protected void grdActivitiesToCopy_OnDetailTableDataBind(object sender, GridDetailTableDataBindEventArgs e){ var tv = e.DetailTableView; var parentItem = e.DetailTableView.ParentItem; var bis = dal.get_booking_informations(); tv.Columns.Add(new GridClientSelectColumn()); var columnNameDict = new Dictionary<string,string>(); var firstDict = true; var dicts = bis.GroupBy(bi=>bi.platsBokadID).Select(group => { var dict = new Dictionary<string, object>(); dict["id"] = "" + group.Key; var list = group.ToList(); if (firstDict) { firstDict = false; var num = 0; var columns = list.Select(header=> { var shortName = "c" + ++num; columnNameDict[header.HeaderName] = shortName; return new GridBoundColumn { DataField = shortName, HeaderText = header.HeaderName }; }); foreach(var column in columns) tv.Columns.Add(column); } var eo = new ExpandoObject(); var eoColl = (ICollection<KeyValuePair<string, object>>)eo; foreach(var header in list) { var shortName = columnNameDict[header.HeaderName]; dict[shortName] = header.Value; } foreach (var kvp in dict) { eoColl.Add(kvp); } dynamic eoDynamic = eo; return eoDynamic; }).ToList(); tv.DataSource = dicts;}
