c# 中的 DataGridView:将属性组合为列,将列表元素组合为列

DataGridView in c#: combining Properties as Columns with elements of a List as Columns

我一直在想这个问题太久了……我真的没主意了。

对我需要实现的目标的解释非常简单。这是我的对象,其中包含一个列表:

class MyObject
{
    public string property1 { get; set; }
    public string property2 { get; set; }
    public List<string> list { get; set; }
}

现在,我需要 DataGridView 的列如下所示:

[property1] | [property2] | [list_element1] | ... | [list_elementN]

数据绑定应该尽可能简单(我的真实对象有两个以上的非列表属性)。

我什至尝试 Reflection 创建一个具有 list_element1, ... , list_elementN 作为属性的动态对象。我有点工作,但在创建 DataGridView 的新行时存在某些问题,所以我放弃了这条路。

关于我的最佳选择有什么想法吗?

我想我找到了一种方法让你做到这一点...(而且我想明确指出我的代码确实很容易出错,但我只是想表明有一线希望,所以请不要不要让我失望)

假设您的数据源是这样的:

List<MyObject> dataSource = new List<MyObject>
{
    new MyObject
    {
        ID = 1,
        Name = "Row1",
        List = new List<string>() {"item1", "item2", "item3"}
    },
    new MyObject
    {
        ID = 2,
        Name = "Row2",
        List = new List<string>() {"item4", "item5", "item6"}
    },
    new MyObject
    {
        ID = 3,
        Name = "Row3",
        List = new List<string>() {"item7", "item8", "item9"}
    }
};

您可以使用现有 MyObject 创建的动态数据源。 (我使用了 ExpandoObject,所以我可以动态地向它添加属性)

List<dynamic> dynamicSource = new List<dynamic>();
foreach (var data in dataSource)
{
    dynamic o = new ExpandoObject();
    // assigning properties we already know
    o.ID = data.ID;
    o.Name = data.Name;

    int idx = 0; // just a counter. you could also do this with a for-loop of course
    foreach (var item in data.List)
    {
        var dict = o as IDictionary<string, Object>; // cast expando object just to get the properties as key and value pairs in a dictionary
        dict.Add("ItemNr" + idx, item);
        idx++;
    }
    dynamicSource.Add(o);
}

现在我发现了一个小的扩展方法here,在这一点上变得非常方便

    public static DataTable ToDataTable(this IEnumerable<dynamic> items)
    {
        var data = items.ToArray();
        if (data.Count() == 0) return null;

        var dt = new DataTable();
        foreach (var key in ((IDictionary<string, object>)data[0]).Keys)
        {
            dt.Columns.Add(key);
        }
        foreach (var d in data)
        {
            dt.Rows.Add(((IDictionary<string, object>)d).Values.ToArray());
        }
        return dt;
    }

现在我们可以像这样将数据源添加到我们的 DataGridView 中:

var dataTable = Extensions.ToDataTable(dynamicSource);
dataGridView1.DataSource = dataTable;

现在应该正确分配了。 我已经测试过,现在添加行应该不是问题。

如果你想取回你的数据源,你必须采取以下小方法:

private List<MyObject> ConvertBackToObject(DataTable dataTable)
    {
        // basically the same procedure as assigning

        List<MyObject> listMyDataSource = new List<MyObject>();
        foreach (DataRow row in dataTable.Rows)
        {
            MyObject myObject = new MyObject
            {
                ID = Convert.ToInt16(row["ID"]),
                Name = row["Name"].ToString(),
                List = new List<string>()
            };

            foreach (var column in dataTable.Columns.Cast<DataColumn>().Where(col => col.ColumnName.StartsWith("ItemNr")))
            {
                myObject.List.Add(row[column].ToString());
            }

            listMyDataSource.Add(myObject);
        }

        return listMyDataSource;
    }

这导致我们这样做(实际上是获取数据源):

DataTable dataTable = dataGridView1.DataSource as DataTable;
// do some null checking here
List<MyObject> myObjects = ConvertBackToObject(dataTable);

这应该会为您提供 MyObject 的更新列表(您现在可以使用它向数据库中插入数据)。

希望它在某种程度上清楚并有所帮助。