Ich habe ein besonderes Problem bei der Implementierung meiner eigenen Sammlung, die IBindingList
unterstützen sollte.Datenbindung in WinForms mit IBindingList schlägt auf leere Liste
Ich habe eine Sammelklasse (DataCollection
) für eine bestimmte Datenklasse (DataItem
). Die Sammlung implementiert die Schnittstellen IBindingList
, IList
, IList<DataItem>
und die DataItem
implementiert INotifyPropertyChanged
(und verfügt über öffentliche Eigenschaften für die Datenbindung).
Wenn ich versuche, um die Sammlung zu einem DataGridView
zu binden, indem die DataSource
Eigenschaft des Rasters einstellen, funktioniert es richtig wenn die Sammlung im Moment der Bindung nicht leer ist. Andernfalls, wenn die Sammlung leer ist, bemerkt das Raster, wenn Zeilen (d. H. DataItems
) hinzugefügt oder aus der Sammlung entfernt werden, die Zellen jedoch leer bleiben. Das Problem besteht darin, dass das Grid die öffentlichen Member der Datenklasse im Fall AutoGenerateColumns=true
nicht erkennt und die Spalten nicht generieren kann.
Was ich auch versucht habe, binde meine DataItems
mit einem BindingList<DataItem>
. In diesem Fall funktioniert das Gitter korrekt, auch wenn die Liste zum Zeitpunkt der Einstellung DataSource
leer ist. Auf der anderen Seite, wenn ich eine BindingList<object>
(aber die gleiche DataItems
als Inhalt) verwenden, ist das Verhalten genauso falsch wie bei meiner DataCollection
. Ich schätze das Problem ist, wenn die Liste zum Zeitpunkt der Bindung leer ist, die Datenbindung den DataItem
Typ nicht richtig erkennt, und es auch nicht später wiederherstellen kann, wenn schließlich Elemente zur Sammlung hinzugefügt werden.
Wichtig ist, dass es funktioniert, wenn die Sammlung zur Bindungszeit nicht leer ist.
Hinweis, dass der gleiche Fehler tritt auf, wenn ich die Spalten angeben:
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;
Ich habe auch versucht true
auf dem AllowNew
meiner IBindingList
zurückzukehren. Das hatte keine beobachtbaren Auswirkungen.
Was versagt auch ist die folgende:
var bindingSource = new BindingSource();
bindingSource.DataSource = myList;
this.dataGridView.DataSource = bindingSource;
Die Frage ist, wie kann ich den Bindungsmechanismus sagen zu meinem DataItems
zu erkennen?
(Danke)
UPDATE 1:
ich ein kleines Testprojekt gemacht, die das Problem zeigt:
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;
}
/// Make a list of type DataItem or object...
//BindingList<object> list = new BindingList<object>() {
BindingList<DataItem> list = new BindingList<DataItem>() {
//new DataItem() {
// Id = 1,
// UserName = "testuser"
//}
};
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"
}
);
// Make some modifications on the data...
(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();
}
}
Wenn die Art der Liste BindingList<DataItem>
ist es korrekt funktioniert. Wenn der Typ BindingList<object>
ist, funktioniert es nur, wenn die Liste beim Initialisieren des nicht leer ist.
Die Lösung funktioniert und ist sehr einfach, ich konnte es einfach nicht finden, das Internet zu suchen. Vielen Dank!! – thaller