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;
}