如何将两个可编辑和可编辑的 DataGridView 绑定到列表和子列表?

How can I have two editable and updatable DataGridViews bounded to a list and sub-list?

我有一个名为 listInputList<Input>,其中包含名为 friendsList<class> 类型的 属性:

List<Input> listInput=new List<Input>();
BindingList<Input> blInput;
BindingSource bsInput;

public class Input
{
    public string Name { get; set; }
    public List<Friend> friends{ get; set; }
}

public class Friend
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

我有两个 DataGridView 控件,分别命名为 dgInputdgFriends
dgInput 像这样绑定到 BindingList

blInput = new BindingList<Input>(listInput);
bsInput = new BindingSource(blInput, null);
dgInput.DataSource = bsInput;

dgInput可编辑 可更新 在 运行 时间在用户更改 [=] 上的任何单元格后17=]。

问题是:如何将 dgFriends 绑定到子列表 friends,以便在 dgInput 当前行更改时自动更新?
当用户更改 dgFriends 上的任何单元格时,可以更新 dgFriens 也很重要(listInput 的属性必须保留更改)。

这是一个简单的例子:

  • 第一个 DataGridView 使用您定义的 BindingSource。此 BindingSource 的 DataSource 设置为 List<Input> 集合。此 DGV 只能显示 List<Input> 中的 Name 属性,因为您无法显示包含单个值和值集合的行。
    BindingSource 的 DataMember 必须为空(或 null):如果将 Name 设置为 DataMember,结果将得到一个 Char 的数组,而不是一个细绳。

  • 创建了第二个 BindingSource:其 DataSource 设置为现有的 BindingSource。在这种情况下,DataMember 被显式设置为 Friends 属性,它表示 List<class> 个对象(单个对象表示将向第二个 DGV 的行)。

这会在两个 BindingSource 对象之间生成一个活动绑定(关系):当第一个 BindingSource.Current 对象更改时,第二个 BindingSource 将随之更改,显示其 Current 对象(List<Friend> 链接到当前 Name 属性)。

这两个 class 的所有属性都是可编辑的。

注:
我已经在 Input class 中实现了 INotifyPropertyChanged 接口来通知 Name 属性 的变化:它不是严格要求的(或者,它不是必需的)完全没有)在这种情况下,但你可能想把它放在那里,你以后很可能会需要它。

List<Input> listInput = new List<Input>();
BindingSource bsInput = null;

public SomeForm()
{
    InitializeComponent();

    bsInput = new BindingSource(listInput, "");
    var bsFriends = new BindingSource(bsInput, "Friends");
    dataGridView1.DataSource = bsInput;
    dataGridView2.DataSource = bsFriends;
}

public class Input : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;
    private string m_Name = string.Empty;

    public string Name {
        get => m_Name;
        set { m_Name = value;
            NotifyPropertyChanged(nameof(this.Name));
        }
    }
    public List<Friend> Friends { get; set; } = new List<Friend>();

    private void NotifyPropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

public class Friend {
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

这是它的工作原理:

示例对象初始化,用于测试:

listInput.AddRange(new[] {
    new Input() {
        Name = "Name One", Friends = new List<Friend>() {
            new Friend () { FirstName = "First", LastName = "Friend of One"},
            new Friend () { FirstName = "Second", LastName = "Friend of One"},
            new Friend () { FirstName = "Third", LastName = "Friend of One"},
        }
    },
    new Input() {
        Name = "Name Two", Friends = new List<Friend>() {
            new Friend () { FirstName = "First", LastName = "Friend of Two"},
            new Friend () { FirstName = "Second", LastName = "Friend of Two"},
            new Friend () { FirstName = "Third", LastName = "Friend of Two"},
        }
    },
    new Input() {
        Name = "Name Three", Friends = new List<Friend>() {
            new Friend () { FirstName = "First", LastName = "Friend of Three"},
            new Friend () { FirstName = "Second", LastName = "Friend of Three"},
            new Friend () { FirstName = "Third", LastName = "Friend of Three"},
        }
    }
});