Binding List <T> a DataGridView in WinForm


91

Ho una lezione

class Person{
      public string Name {get; set;}
      public string Surname {get; set;}
}

e una List<Person>a cui aggiungo alcune voci. L'elenco è vincolato al mio DataGridView.

List<Person> persons = new List<Person>();
persons.Add(new Person(){Name="Joe", Surname="Black"});
persons.Add(new Person(){Name="Misha", Surname="Kozlov"});
myGrid.DataSource = persons;

Non c'è problema. myGridmostra due righe, ma quando aggiungo nuovi elementi al mio personselenco, myGridnon mostra il nuovo elenco aggiornato. Mostra solo le due righe che ho aggiunto prima.

Quindi qual'è il problema?

Il rebinding ogni volta funziona bene. Ma quando associo un DataTablealla griglia quando ogni volta che DataTableapporto delle modifiche non c'è bisogno di ReBind myGrid.

Come risolverlo senza ripetere ogni volta?

Risposte:


187

L'elenco non viene implementato, IBindingListquindi la griglia non conosce i tuoi nuovi elementi.

Associa invece il tuo DataGridView a un file BindingList<T>.

var list = new BindingList<Person>(persons);
myGrid.DataSource = list;

Ma vorrei anche andare oltre e legare la tua griglia a un file BindingSource

var list = new List<Person>()
{
    new Person { Name = "Joe", },
    new Person { Name = "Misha", },
};
var bindingList = new BindingList<Person>(list);
var source = new BindingSource(bindingList, null);
grid.DataSource = source;

Si dice che è possibile utilizzare IList e altre interfacce aswell: msdn.microsoft.com/en-us/library/...
Pacane

4
@ Pacane: Certo che puoi, ma DataGridView deve sapere se la tua origine dati ha delle modifiche. OneIl modo è usare un BindingList, che genererà un evento se l'elenco sottostante cambia. Un altro modo è usare BindingSourcee chiamare ResetBinding () ogni volta che aggiungi / elimini una riga, ma questo è molto più lavoro. Se si desidera informare la griglia sui cambiamenti di proprietà, il modo più semplice è implementareINotifyPropertyChanged
Jürgen Steinblock,

5
perché hai usato BindingList e BindingSource perché possiamo associare direttamente l'elenco alla proprietà datasource di datagridview. discutere l'importanza di BindingList e BindingSource u utilizzati qui. grazie
Mou

5
@Mou Puoi associare un DataGrid a un List<T>se vuoi. Ma se si aggiungono programmaticamente elementi a List, DataGridView non lo saprà perché List non impianta IBindingList. Per quanto riguarda BindingSource: Uso molto i winform e non mi associo a nient'altro che a BindingSource - FULLSTOP. Aggiungere più dettagli è troppo per un commento, ma BindingSourceha così tanto da offrire senza svantaggi. Anyone who does not use a BindingSource for binding has not fully understood windows forms databindings
Andrei

4
@CraigBrett Consideralo BindingSourcecome un ponte tra la tua origine dati e la tua GUI. Risolve molti problemi relativi all'associazione di dati. Vuoi ricaricare i tuoi dati? Basta impostare la bindingSource.DataSourcetua nuova raccolta invece di riassociare ogni controllo. Il tuo DataSource può essere nullo? Imposta bindingSource.DataSource = typeof(YourClass)Vuoi avere una griglia modificabile ma la tua origine dati non ha un costruttore senza parametri? Basta implementare l' bindingSource.AddingNewevento e creare l'oggetto da soli. Non ho mai sperimentato uno svantaggio durante l'utilizzo, BindingSourcema molti vantaggi.
Jürgen Steinblock

4

Ogni volta che aggiungi un nuovo elemento all'elenco devi rilegare la tua griglia. Qualcosa di simile a:

List<Person> persons = new List<Person>();
persons.Add(new Person() { Name = "Joe", Surname = "Black" });
persons.Add(new Person() { Name = "Misha", Surname = "Kozlov" });
dataGridView1.DataSource = persons;

// added a new item
persons.Add(new Person() { Name = "John", Surname = "Doe" });
// bind to the updated source
dataGridView1.DataSource = persons;

Non riesco a vedere la proprietà dataSource sotto datagrid, puoi dirmi come si usa?
RSB

2

Sì, è possibile eseguire il rebinding implementando l'interfaccia INotifyPropertyChanged.

Un esempio abbastanza semplice è disponibile qui,

http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx


1
Ciò non è sufficiente, se implementi INotifyPropertyChangedDataGridView mostrerà tutte le modifiche alle proprietà che avvengono in background, ma non saprà se aggiungi / elimini una riga dalla tua fonte. A tale scopo è presente IBindingListun'interfaccia e, per vostra comodità, BindingList<T>un'implementazione che già lo implementa, ma non supporta l'ordinamento / filtraggio.
Jürgen Steinblock

1
Sì, sono d'accordo con te. quindi penso che ObservableCollection <T> possa essere utilizzato per questo. Cosa ne pensi?
Dev

0

Dopo aver aggiunto un nuovo elemento da personsaggiungere:

myGrid.DataSource = null;
myGrid.DataSource = persons;

Non riesco a vedere la proprietà dataSource sotto datagrid, puoi dirmi come si usa?
RSB

1
Questo suggerimento potrebbe causare problemi. Ad esempio, potresti scoprire che un clic su un elemento nella griglia potrebbe ottenere un'eccezione IndexOutOfRangeException poiché l'origine dati è nulla in quel punto. Sarebbe più saggio legarsi a un BindingList inizialmente e implementare INotifyPropertyChanged sul tuo oggetto come indicano altre risposte
steve

A che scopo assegnarlo nullse lo assegni immediatamente alla personsriga successiva?
Rufus L

0

Questo non è esattamente il problema che ho avuto, ma se qualcuno sta cercando di convertire un BindingList di qualsiasi tipo in un elenco dello stesso tipo, allora è così:

var list = bindingList.ToDynamicList();

Inoltre, se stai assegnando BindingLists di tipi dinamici a DataGridView.DataSource, assicurati di dichiararlo prima come IBindingList in modo che funzioni sopra.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.