I have a particular problem with implementing my own collection, which should support IBindingList.
I have a collection class ( DataCollection) for a specific data class ( DataItem). Collection implements interfaces IBindingList, IList, IList<DataItem>and DataItemrealizes INotifyPropertyChanged(and has public properties for data binding).
When I try to bind a collection to DataGridViewby setting the DataSourcegrid property , it works correctly if the collection is not empty at the time of the binding. Otherwise, if the collection is empty, the grid notices when the rows (i.e. DataItems) are added or removed from the collection, but the cells remain empty. The problem is that the grid does not recognize public members of the data class in the case AutoGenerateColumns=trueand cannot generate columns.
I also tried linking my DataItemswith BindingList<DataItem>. In this case, the grid works correctly even if the list is empty at the time of installation DataSource. On the other hand, if I use BindingList<object>(but the same DataItemsas content), the behavior is as bad as mine DataCollection. I think the problem is that if the list is empty at the time of the binding, the data binding will not be able to correctly determine the type DataItem, nor will it be able to recover later when finally elements are added to the collection.
It is important that it works if the collection is not empty during binding.
Note that the same error occurs when I specify the columns:
this.dataGridView.ReadOnly = true;
this.dataGridView.AutoGenerateColumns = false;
DataGridViewTextBoxColumn column;
column = new DataGridViewTextBoxColumn();
column.DataPropertyName = "Id";
column.HeaderText = "Id";
this.dataGridView.Columns.Add(column);
column = new DataGridViewTextBoxColumn();
column.DataPropertyName = "UserName";
column.HeaderText = "UserName";
this.dataGridView.Columns.Add(column);
this.dataGridView.DataSource = myList;
I also tried to return trueto AllowNewmine IBindingList. This had no noticeable effect.
What also fails is the following:
var bindingSource = new BindingSource();
bindingSource.DataSource = myList;
this.dataGridView.DataSource = bindingSource;
, , DataItems?
()
1:
, :
public partial class Form1: Form {
public Form1() {
InitializeComponent();
}
class DataItem: INotifyPropertyChanged {
private int _id;
public int Id {
get {
return _id;
}
set {
if (value != _id) {
_id = value;
OnPropertyChanged("Id");
}
}
}
private string _userName;
public string UserName {
get {
return _userName;
}
set {
if (value != _userName) {
_userName = value;
OnPropertyChanged("UserName");
}
}
}
private void OnPropertyChanged(string propertyName) {
var handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
BindingList<DataItem> list = new BindingList<DataItem>() {
};
private void Form1_Load(object sender, EventArgs e) {
DataGridView dataGridView = new System.Windows.Forms.DataGridView();
dataGridView.Size = new Size(this.Width-20, this.Height-30);
dataGridView.AutoGenerateColumns = true;
DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
column.DataPropertyName = "Id";
column.HeaderText = "Id";
dataGridView.Columns.Add(column);
this.Controls.Add(dataGridView);
dataGridView.DataSource = list;
list.Add(
new DataItem() {
Id = 3,
UserName = "admin"
}
);
(new System.Threading.Thread( state => {
System.Threading.Thread.CurrentThread.IsBackground = true;
System.Threading.Thread.Sleep(2000);
this.Invoke( (Action)( () => {
list.Add(new DataItem() {
Id = 2,
UserName = "guest"
});
} ) );
System.Threading.Thread.Sleep(2000);
this.Invoke( (Action)( () => {
DataItem user = (list.First( obj => ((DataItem)obj).Id == 3 )) as DataItem;
user.UserName = "Administrator";
} ) );
})).Start();
}
}
BindingList<DataItem>, . BindingList<object> , DataSource.