This solution helps to populate dgv but since anonymous types are immutable such grid cannot be edited but even otherwise I dont't think it would have helped with 2-way binding
List<int> values = GetValues();
var dataGridView = new DataGridView();
dataGridView.DataSource = values.Select(el => new { Value = el }).ToList();
Using wrapper class allows me to edit cells but changes are not reflected on the original collection
public class Wrapper<T>
{
public T Value { get; set; }
public Wrapper(T value) => Value = value;
}
...
dataGridView.DataSource = new BindingList<Wrapper<int>>(values.Select(value => new Wrapper<int>(value)).ToList());
So how do you make it work?
Two-way databinding works based on change notification of the data source. Here your data source is List<int>
, neither List<T>
nor int
raises change notification, thus two-way databinding doesn't make sense here.
Assuming you want to implement two-way databinding of BindingList<int>
with DataGridView
, here is what you can do:
BindingList<int> originalBindingList;
private void Form1_Load(object sender, EventArgs e)
{
originalBindingList = new BindingList<int>(new List<int> { 1, 2, 3 });
dataGridView1.DataSource = new ListDataSource<int>(originalBindingList);
}
Then:
DataGridView
will show you a Value
column and rows containing the originalBindingList
values.DataGridView
the values in originalBindingList
will change.originalBindingList
in code, DataGridView
will refresh values.And here is ListDataSource:
public class ListDataSource<T> : BindingSource
{
public ListDataSource(BindingList<T> original)
{
for (int i = 0; i < original.Count; i++)
{
this.Add(new Item(original, i));
}
original.ListChanged += (obj, args) =>
this.OnListChanged(new ListChangedEventArgs(
args.ListChangedType, args.NewIndex));
}
private class Item : INotifyPropertyChanged
{
IList<T> source;
int index;
public Item(IList<T> source, int index)
{
this.source = source;
this.index = index;
}
public T Value
{
get { return source[index]; }
set
{
source[index] = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}