简体   繁体   English

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

[英]How does DataGridView get the list of properties in a class?

When you set a List or, even better, a BindingList as the source of a DataGridView, it gets the list of properties and uses them to generate columns. 当您设置List或者更好的是将BindingList作为DataGridView的源时,它会获取属性列表并使用它们来生成列。

If I do the following: 如果我执行以下操作:

        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;

Nothing happens. 什么都没发生。 No columns or rows are ever added to the DataGridView. 没有任何列或行被添加到DataGridView。 I'm guessing that's because there is a method missing that allows the DataGridView to get the collection of properties. 我猜这是因为缺少一个允许DataGridView获取属性集合的方法。

If I run the same code but replace ExpandoObject with MyCustomClass in the code sample above, as defined below, the DataGridView would populate just fine. 如果我运行相同的代码,但在上面的代码示例中使用MyCustomClass替换ExpandoObject,如下所定义,DataGridView将填充正常。

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

However, since I'm reading my data from a source that may change, I need to use a dynamic class. 但是,由于我从可能发生变化的源读取数据,因此我需要使用动态类。 I've tried a number of methods including a BindingList BindigList> none of which will bind the dynamic members to column. 我尝试了很多方法,包括BindingList BindigList>都没有将动态成员绑定到列。 I've even tried creating a class that inherits DynamicObject with overrides for TryGetMember and TrySetMember. 我甚至尝试使用TryGetMember和TrySetMember的覆盖创建一个继承DynamicObject的类。

I feel like I'm spinning my wheels and overlooking a simple solution. 我觉得我正在转动轮子,忽略了一个简单的解决方案。 Maybe there's some trick using a Dictionary and Linq that I'm missing here. 也许有一些技巧使用我在这里缺少的Dictionary和Linq。

Caveats: I'm collecting data, summarizing it and displaying it. 注意事项:我正在收集数据,总结并显示数据。 I don't need to add or remove data once it's been displayed. 一旦显示数据,我就不需要添加或删除数据。 I will be trying to filter and sort it though. 我会尝试过滤和排序它。 I'll cross that bridge, though, once I figure out how to show it. 不过,一旦我弄明白如何展示它,我就会越过那座桥。

My example shows simple known values and types, but my actual source data will be less predictable and it is parsed from JSON using Newtonsoft JSON with a structure as follows: 我的示例显示了简单的已知值和类型,但我的实际源数据将不太可预测,并且使用Newtonsoft JSON从JSON解析,结构如下:

[ { "match_number": 1, "set_number": 1, "key": "2017onbar_f1m1", "score_breakdown": { "blue": { "totalPoints": 236, "foulCount": 1, "adjustPoints": 0, "overtime": true }, "red": { "totalPoints": 236, "foulCount": 1, "adjustPoints": 0, "overtime": true } }, "teammembers": { "blue": { "teams": [ "member1", "member2", "member3" ] }, "red": { "teams": [ "member4", "member5", "member6" ] } } }] [{“match_number”:1,“set_number”:1,“key”:“2017onbar_f1m1”,“score_breakdown”:{“blue”:{“totalPoints”:236,“foulCount”:1,“adjustPoints”:0, “加班”:真实},“红色”:{“totalPoints”:236,“foulCount”:1,“adjustPoints”:0,“加班”:真}},“teammembers”:{“blue”:{“团队“:[”member1“,”member2“,”member3“]},”red“:{”teams“:[”member4“,”member5“,”member6“]}}}]

However, the score_breakdown fields will vary. 但是,score_breakdown字段会有所不同。

Try converting your BindingList into DataTable 尝试将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;

    }

In case when given datasource is instance of some type (not instance of Type ) DatagridView.DataSource setter will use source.GetType().GetProperties() for retrieving properties, which will be used for generating columns. 如果给定的datasource是某种类型的实例(不是Type实例), DatagridView.DataSource setter将使用source.GetType().GetProperties()来检索属性,这些属性将用于生成列。

Problem is that in your case type ExpandoObject will return empty collection 问题是在你的情况下类型ExpandoObject将返回空集合

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

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

Because you know name of properties in compile time you can use new features of C# and create tuple 因为您在编译时知道属性的名称,所以可以使用C#的新功能并创建元组

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

But again - if you know properties names at compile time why not create a class for it? 但是再次 - 如果您在编译时知道属性名称,为什么不为它创建一个类?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM