2010-11-20 5 views
3

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.

Antwort

7

Die Datenbindung beginnt mit einem Blick auf die Listenelemente, um ihre Eigenschaften zu ermitteln. Bei einer leeren Liste werden jedoch alle Informationen aus der Liste der Elemente aus der Type abgerufen. Der Grund, warum die Datenbindung keine Eigenschaften erkennen kann, wenn Sie eine leere verwenden, ist, dass object keine bindbaren Eigenschaften hat.

Um sicherzustellen, dass Ihre DataCollection Klasse ordnungsgemäß die Bindung unterstützt, auch wenn sie leer ist, implementieren Sie die ITypedList Schnittstelle. Es enthält die Methode GetItemProperties(), mit der Sie explizit angeben können, welche Eigenschaften bindbar sind. Innerhalb dieser Methode können Sie die folgende verwenden, um die Eigenschaften auf DataItem zurückzukehren:

return TypeDescriptor.GetProperties(typeof(DataItem)); 

Auf diese Weise, auch wenn die Sammlung leer ist, die Datenbindung wissen, welche Eigenschaften zu zeigen.

+0

Die Lösung funktioniert und ist sehr einfach, ich konnte es einfach nicht finden, das Internet zu suchen. Vielen Dank!! – thaller

Verwandte Themen