DataGridView如何获取类中的属性列表?

时间:2017-04-14 05:54:20

标签: c# datagridview dynamicobject

当您设置List或更好的BindingList作为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&gt;其中没有一个会将动态成员绑定到列。我甚至尝试使用TryGetMember和TrySetMember的覆盖创建一个继承DynamicObject的类。

我觉得我在旋转车轮,忽略了一个简单的解决方案。也许使用我在这里缺少的词典和Linq的一些技巧。

警告:我正在收集数据,汇总数据并显示数据。我不需要在显示数据后添加或删除数据。我会尝试过滤和排序它。不过,一旦我弄清楚如何展示它,我就会越过那座桥。

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

[   {     &#34; match_number&#34;:1,     &#34; set_number&#34;:1,     &#34; key&#34;:&#34; 2017onbar_f1m1&#34;,     &#34; score_breakdown&#34;:{       &#34;蓝&#34;:{         &#34; totalPoints&#34;:236,         &#34; foulCount&#34;:1,         &#34; adjustPoints&#34;:0,         &#34;加班&#34;:是的       },       &#34; red&#34;:{         &#34; totalPoints&#34;:236,         &#34; foulCount&#34;:1,         &#34; adjustPoints&#34;:0,         &#34;加班&#34;:是的       }     },     &#34; teammembers&#34;:{       &#34;蓝&#34;:{         &#34;团队&#34;:[           &#34;的member1&#34 ;,           &#34; member2&#34 ;,           &#34; member3&#34;         ]       },       &#34; red&#34;:{         &#34;团队&#34;:[           &#34; member4&#34 ;,           &#34; member5&#34 ;,           &#34; member6&#34;         ]       }     }   }]

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

2 个答案:

答案 0 :(得分:0)

尝试将BindingList转换为DataTable

    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;

    }

答案 1 :(得分:0)

如果给定的数据源是某种类型的实例(不是Type的实例)DatagridView.DataSource,setter将使用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" );

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