I have a List<Input>
named listInput
that contains property of type a List<class>
named friends
:
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; }
}
I have two DataGridView
controls, named dgInput
and dgFriends
.
dgInput
is bound to a BindingList
like this:
blInput = new BindingList<Input>(listInput);
bsInput = new BindingSource(blInput, null);
dgInput.DataSource = bsInput;
dgInput
is editable and updatable at run-time after user changes any cell on dgInput
.
The question is: how can I bind dgFriends
to sublist friends
, so that it will automatically update when the dgInput
curretn Row changes?
It's also important that dgFriens
can be updated when an User changes any cell on dgFriends
(the properties of listInput
must preserve the changes).
Here's a simple example:
The first DataGridView uses the BindingSource you defined. The DataSource of this BindingSource is set to the List<Input>
collection. This DGV can only show the Name
property from the List<Input>
, since you cannot present Rows containing both single values and collections of values.
The DataMember
of the BindingSource must be empty (or null): if you set Name
as DataMember
, you'll get an array of Char
as a result instead of a string.
A second BindingSource is created: its DataSource is set to the existing BindingSource. In this case, the DataMember
is set explicitly to the Friends
property, which represents a List<class>
objects (a single object that represents a collection that will provide the data to the Rows of the second DGV).
This generates an active binding (a relationship) between the two BindingSource objects: when the first BindingSource.Current
object changes, the second BindingSource will follow, showing its Current
object (the List<Friend>
linked to the current Name
property).
All properties of the two classes are editable.
Note:
I've implemented the INotifyPropertyChanged interface in the Input
class to notify changes of the Name
property: it's not strictly required (or, it' not required at all) in this context, but you may want to have it there, you'll quite probably need it later.
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; }
}
This is how it works:
Sample object initialization, for testing:
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"},
}
}
});