gpt4 book ai didi

c# - DataGridView 数据绑定(bind)到 List>

转载 作者:行者123 更新时间:2023-12-02 02:24:21 25 4
gpt4 key购买 nike

给定代码

class Foo {
public string Value {get; set;}
public int Id {get; set;}
}
List<List<Foo>> fooList = new List<List<Foo>>();

有没有办法将 Multidim ICollection 绑定(bind)到属性 Value 上的 DataGridView,当您更改单元格时,对象的 Value 属性会更新?

在这种情况下,列表中 Foo 的每个实例将代表 DataGridView 中的一个单元格,并且行/列将被保留,就像它们在 multidim ICollection 中一样

我所说的 Multidim 的意思是:

List<List<Foo>] => [
List<Foo> => [0,1,2,3,4,5]
List<Foo> => [0,1,2,3,4,5]
List<Foo> => [0,1,2,3,4,5]
List<Foo> => [0,1,2,3,4,5]
]

嵌套列表中的每个元素实际上都是 Foo 的实例。

最佳答案

实现IListSource并在内部映射到DataTabe

您可以创建一个实现 IListSource 的自定义数据源并将其设置为DataGridView的数据源。正确实现接口(interface)以满足您的要求:

  • 在构造函数中,接受原始列表并将其映射到 DataTable
  • 订阅ListChanged数据表的 DefaultView 属性的事件并将更改应用到原始列表。
  • 对于GetList方法,返回映射的数据表。

然后,当您将 DataGridView 绑定(bind)到新数据源时,所有编辑操作都会立即反射(reflect)在您的原始列表中:

dataGridView1.DataSource = new FooDataSource(yourListOfListOfFoo);

ListListDataSource实现

public class ListListDataSource<T> : IListSource
{
List<List<T>> data;
DataTable table;
public ListListDataSource(List<List<T>> list)
{
this.data = list;
table = new DataTable();
for (int i = 0; i < list.First().Count(); i++)
{
TypeDescriptor.GetProperties(typeof(T)).Cast<PropertyDescriptor>()
.Where(p => p.IsBrowsable).ToList().ForEach(p =>
{
if (p.IsBrowsable)
{
var c = new DataColumn($"[{i}].{p.Name}", p.PropertyType);
c.ReadOnly = p.IsReadOnly;
table.Columns.Add(c);
}
});
}
foreach (var innerList in list)
{
table.Rows.Add(innerList.SelectMany(
x => TypeDescriptor.GetProperties(typeof(T)).Cast<PropertyDescriptor>()
.Where(p => p.IsBrowsable).Select(p => p.GetValue(x))).ToArray());
}
table.DefaultView.AllowDelete = false;
table.DefaultView.AllowNew = false;
table.DefaultView.ListChanged += DefaultView_ListChanged;
}

public bool ContainsListCollection => false;
public IList GetList()
{
return table.DefaultView;
}
private void DefaultView_ListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType != ListChangedType.ItemChanged)
throw new NotSupportedException();
var match = Regex.Match(e.PropertyDescriptor.Name, @"\[(\d+)\]\.(\w+)");
var index = int.Parse(match.Groups[1].Value);
var propertyName = match.Groups[2].Value;
typeof(T).GetProperty(propertyName).SetValue(data[e.NewIndex][index],
table.Rows[e.NewIndex][e.PropertyDescriptor.Name]);
}
}

然后将您的列表绑定(bind)到 DataGridView,如下所示:

List<List<Foo>> foos;
private void Form1_Load(object sender, EventArgs e)
{
foos = new List<List<Foo>>{
new List<Foo>(){
new Foo() { Id=11, Value="11"}, new Foo() { Id = 12, Value = "12" }
},
new List<Foo>() {
new Foo() { Id=21, Value="21"}, new Foo() { Id = 22, Value = "22" }
},
};
dataGridView1.DataSource = new ListListDataSource<Foo>(foos);
}

enter image description here

当您在DataGridView中编辑数据时,实际上您正在编辑原始列表。

此外,如果您想隐藏某个属性,只需将 [Browsable(false)] 添加到该属性即可:

public class Foo
{
[Browsable(false)]
public int Id { get; set; }
public string Value { get; set; }
}

enter image description here

关于c# - DataGridView 数据绑定(bind)到 List<List<T>>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65925733/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com