DataGridView 数据绑定到 List<List<T>> [英] DataGridView Databinding to List&lt;List&lt;T&gt;&gt;

查看:58
本文介绍了DataGridView 数据绑定到 List<List<T>>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定代码

class Foo {公共字符串值 {get;放;}公共 int Id {get;放;}}列表<列表<Foo>>fooList = new List>();

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

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

Multidim 的意思是:

List] =>[列表=>[0,1,2,3,4,5]列表=>[0,1,2,3,4,5]列表=>[0,1,2,3,4,5]列表=>[0,1,2,3,4,5]]

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

解决方案

内部实现 IListSource 并映射到 DataTabe

您可以创建一个自定义数据源来实现

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

另外,如果你想隐藏一个属性,就像在属性中添加[Browsable(false)]一样简单:

公共类Foo{[可浏览(假)]公共 int Id { 获取;放;}公共字符串值 { 获取;放;}}

Given the code

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

Is there a way to bind a Multidim ICollection to a DataGridView on the property Value, where when you change a cell, the Value property of the object updates?

In this case, each instance of Foo in the list will represent one cell in the DataGridView and the rows/ columns are being preserved as they would be in the multidim ICollection

By Multidim I mean something to the affect of:

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]
]

Where each element in the nested list is actually and instance of Foo.

解决方案

Implementing IListSource and mapping to DataTabe internally

You can create a custom data source which implements IListSource and set it as data source of DataGridView. To implement the interface properly to satisfy your requirement:

  • In constructor, accept original list and map it to a DataTable.
  • Subscribe to ListChanged event of the DefaultView property of you data table and apply changes to your original list.
  • For GetList method, return the mapped data table.

Then when you bind DataGridView to your new data source, all the editing operations will immediately reflect in your original list:

dataGridView1.DataSource = new FooDataSource(yourListOfListOfFoo);

ListListDataSource Implementation

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]);
    }
}

Then bind your list to DataGridView like this:

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);
}

And when you edit data in DataGridView, in fact you are editing the original list.

Also if you want to hide a property, it's as easy as adding [Browsable(false)] to the property:

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

这篇关于DataGridView 数据绑定到 List<List<T>>的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆