Using list of Dictionary as datasource for DetailTableViews?

4 posts, 0 answers
  1. Ingemar
    Ingemar avatar
    17 posts
    Member since:
    Apr 2012

    Posted 14 Sep Link to this post

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

     

  2. Eyup
    Admin
    Eyup avatar
    3005 posts

    Posted 19 Sep Link to this post

    Hello Ingemar,

    The data source of the grid should contain properties as fields. In your case you can use anonymous types and LINQ projection. Return the following collection instead of Dictionary:
    e.DetailTableView.DataSource=bis.Select(x=>new { FieldID = some id, FieldString = "some value",  FieldDate = some date, etc.});

    That should do the trick.

    Regards,
    Eyup
    Telerik by Progress
    Do you need help with upgrading your ASP.NET AJAX, WPF or WinForms projects? Check the Telerik API Analyzer and share your thoughts.
  3. UI for ASP.NET Ajax is Ready for VS 2017
  4. Ingemar
    Ingemar avatar
    17 posts
    Member since:
    Apr 2012

    Posted 03 Oct in reply to Eyup Link to this post

    But how will that anonymous object be able to contain a dynamic number of properties then?
  5. Eyup
    Admin
    Eyup avatar
    3005 posts

    Posted 06 Oct Link to this post

    Hello Ingemar,

    This depends solely on your code-behind logic and it is not related specifically to RadGrid control functionality. If you plan to dynamically change the fields and columns of the grid, you can check the following article:
    http://www.telerik.com/help/aspnet-ajax/grid-changing-structure-dynamically.html

    Regards,
    Eyup
    Telerik by Progress
    Do you need help with upgrading your ASP.NET AJAX, WPF or WinForms projects? Check the Telerik API Analyzer and share your thoughts.
Back to Top