Вот простой пример:
Первый DataGridView использует определенный BindingSource. Источник данных этого BindingSource установлен в коллекцию List<Input>
. Этот DGV может отображать только свойство Name
из List<Input>
, поскольку вы не можете представить строки, содержащие как отдельные значения, так и наборы значений.
DataMember
BindingSource должен быть пустым (или нулевым): если вы установите Name
как DataMember
, в результате вы получите массив Char
вместо строки.
Создается второй BindingSource: его DataSource установлен на существующий BindingSource. В этом случае DataMember
явно устанавливается в свойство Friends
, которое представляет объекты List<class>
(один объект, представляющий коллекцию, которая будет предоставлять данные в строки второго DGV).
Генерирует активное связывание (связь) между двумя объектами BindingSource: при изменении первого объекта BindingSource.Current
будет следовать второй объект BindingSource, показывая его Current
объект (List<Friend>
, связанный с текущим свойством Name
).
Все свойства двух классов доступны для редактирования.
Примечание:
Я реализовал интерфейс INotifyPropertyChanged в классе Input
для уведомления об изменениях свойства 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"},
}
}
});