2017-04-14 72 views
1

当您设置List或甚至更好的BindingList作为DataGridView的源时,它将获取属性列表并使用它们来生成列。DataGridView如何获取类中属性的列表?

如果我做到以下几点:

 StatsList = new BindingList<ExpandoObject>(); 

     // Add seed record to generate columns in DataGridView 
     dynamic ds = new ExpandoObject(); 

     ds.key = "0000"; 
     ds.Name = "Bob"; 
     ds.Number = "2255442"; 

     ds.key = "0001"; 
     ds.Name = "Nathan"; 
     ds.Number = "1217479"; 

     StatsList.Add(ds); 

     dgvListView.DataSource = StatsList; 

什么也没有发生。 DataGridView中没有添加任何列或行。我猜这是因为有一个方法丢失,允许DataGridView获取属性的集合。

如果我在上面的代码示例中运行相同的代码,但用MyCustomClass代替ExpandoObject,如下所述,DataGridView将填充得很好。

public class MyCustomClass 
{ 
    public string key { get; set; } 
    public string name { get; set; } 
    public string number { get; set; } 
} 

但是,由于我正在从可能更改的源读取数据,因此需要使用动态类。我已经尝试了很多方法,包括一个BindingList BindigList>它们都不会将动态成员绑定到列。我甚至尝试创建一个继承DynamicObject的类,并重写TryGetMember和TrySetMember。

我觉得我正在旋转我的车轮,并忽略了一个简单的解决方案。也许有一些技巧使用我在这里失踪的Dictionary和Linq。

注意事项:我正在收集数据,总结并显示它。一旦显示数据,我不需要添加或删除数据。我会尽力筛选和排序。但是,一旦我弄清楚如何展示它,我会穿过那座桥。

我的例子示出了简单的已知值和类型,但我的实际的源数据将是较不可预测并且从JSON使用Newtonsoft JSON用结构解析如下:

[ { “match_number”:1 , “SET_NUMBER”:1, “键”: “2017onbar_f1m1”, “score_breakdown”:{ “蓝色”:{ “totalPoints”:236, “foulCount”:1, “adjustPoints”:0, “加班”:真 }, “红”:{ “totalPoints”:236, “foulCount”:1, “adjustPoints”:0, “加班”:真 } }, “teammembers”:{ “蓝色”:{ “团队”:[ “的member1”, “member2”, “member3” ] }, “红色”:{ “团队”:[ “member4”, “member5”, “member6” ] } } }]

但是,score_breakdown字段会有所不同。

+0

为datagridview使用'dynamic'的目的是什么? 'DataGridView.DataSource'是所有其他强类型对象的集合。 – Fabio

+0

看起来像XY问题,你可以显示你从那个来源得到什么样的数据(格式)? – Fabio

+0

源数据有点大,但源代码是使用Newtonsoft.JSON转换的JSON。一些结构将保持不变,但有些会有所不同。 – Prdufresne

回答

0

尝试中的BindingList转换成数据表

protected void Page_Load(object sender, EventArgs e) 
    { 
     var StatsList = new BindingList<ExpandoObject>(); 

     // Add seed record to generate columns in DataGridView 
     dynamic ds = new ExpandoObject(); 

     ds.key = "0000"; 
     ds.Name = "Bob"; 
     ds.Number = "2255442"; 

     dynamic ds2 = new ExpandoObject(); 

     ds2.key = "0001"; 
     ds2.Name = "Nathan"; 
     ds2.Number = "1217479"; 

     StatsList.Add(ds); 
     StatsList.Add(ds2); 


     GridView1.DataSource = ExpandoListToDataTable(StatsList); 

     GridView1.DataBind(); 
    } 

    protected DataTable ExpandoListToDataTable(BindingList<ExpandoObject> d) 
    { 
     var dt = new DataTable(); 

     foreach (var a in d) 
     { 
      foreach (var key in ((IDictionary<string, object>)a).Keys) 
      { 
       if (!dt.Columns.Contains(key)) 
       { 
        dt.Columns.Add(key); 
       } 
      } 

      dt.Rows.Add(((IDictionary<string, object>)a).Values.ToArray()); 
     } 

     return dt; 

    } 
+0

我会试一试。谢谢。 – Prdufresne

+0

谢谢@Jury_Golubev。我想你已经把我推向了与我计划不同的方向,但我认为这个选择最终会更好。使用ExpandoObject可能是错误的方法,因为我正在尝试做的事情,我认为使用List of Dictionaries和一个方法将它们转换为DataTable表示会更好。更干净。谢谢! – Prdufresne

0

如果给定的数据源时是某种类型的(未的Type实例)DatagridView.DataSource设定器将使用source.GetType().GetProperties()用于检索属性,这将被用于生成列的实例。

问题是,在你的案件类型ExpandoObject将返回空集

dynamic ds = new ExpandoObject(); 
ds.key = "0000"; 
ds.Name = "Bob"; 
ds.Number = "2255442"; 

ds.GetType().GetProperties() // return empty collection 

因为你知道在编译时属性的名称,你可以使用C#的新特性,创造元组

var ds = (key: "0000", Name: "Bob", Number: "2255442"); 

但再次 - 如果您在编译时知道属性名称,为什么不为它创建类?

+0

在我提供的相同代码中,我只是添加了一些示例数据,但在我的实际应用程序中,我正在解析JSON对象中的数据,因此直到运行时才会知道这些属性。我曾尝试创建一个包含内部字典和自定义GetPropoerties方法的类,但这似乎不适用于我,可能是因为我错误地格式化了Ilist – Prdufresne