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 的更新列表(您现在可以使用它向数据库中插入数据)。
希望它在某种程度上清楚并有所帮助。
我一直在想这个问题太久了……我真的没主意了。
对我需要实现的目标的解释非常简单。这是我的对象,其中包含一个列表:
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 的更新列表(您现在可以使用它向数据库中插入数据)。
希望它在某种程度上清楚并有所帮助。