2013-02-28 12 views
7

Desidero essere in grado di associare un elenco a un'origine dati casella di riepilogo e quando l'elenco viene modificato, l'interfaccia utente della casella di riepilogo viene aggiornata automaticamente. (Winforms non ASP). Ecco un esempio:Bind List a DataSource

private List<Foo> fooList = new List<Foo>(); 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     //Add first Foo in fooList 
     Foo foo1 = new Foo("bar1"); 
     fooList.Add(foo1); 

     //Bind fooList to the listBox 
     listBox1.DataSource = fooList; 
     //I can see bar1 in the listbox as expected 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     //Add anthoter Foo in fooList 
     Foo foo2 = new Foo("bar2"); 
     fooList.Add(foo2); 
     //I expect the listBox UI to be updated thanks to INotifyPropertyChanged, but it's not 
    } 

class Foo : INotifyPropertyChanged 
{ 
    private string bar_ ; 
    public string Bar 
    { 
     get { return bar_; } 
     set 
     { 
      bar_ = value; 
      NotifyPropertyChanged("Bar"); 
     } 
    } 

    public Foo(string bar) 
    { 
     this.Bar = bar; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void NotifyPropertyChanged(string info) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     } 
    } 

    public override string ToString() 
    { 
     return bar_; 
    } 
} 

Se sostituisco List<Foo> fooList = new List<Foo>(); da BindingList<Foo> fooList = new BindingList<Foo>(); allora funziona. Ma non voglio cambiare il tipo originale di follista. Vorrei qualcosa di simile al lavoro: listBox1.DataSource = new BindingList<Foo>(fooList);

EDIT: Inoltre ho appena letto qui List<T> vs BindingList<T> Advantages/DisAdvantages da Ilia Jerebtsov: "Quando si imposta DataSource del BindingSource a un elenco <>, si crea internamente un BindingList per avvolgere la lista". Penso che il mio esempio dimostri solo che questo non è vero: la mia lista <> non sembra essere internamente racchiusa in un BindingList <>.

+0

Elenco <> non genera eventi per gli osservatori per sapere quando eseguire l'aggiornamento. Non importa se l'osservatore è un componente dell'interfaccia utente o un altro elenco che funge da wrapper. Perché l'obiezione a cambiare a BindingList quando è vincolante è ciò che devi fare? – JRoughan

+0

Non desidero modificare l'elenco in BindingList perché è già utilizzato come elenco ovunque nel progetto. Dovrò sostituire ogni firma di metodo, voglio evitare di modificare ciò che è già stabile. – Michael

+0

Cosa succede se hai cambiato il tipo di ritorno in IList ? Hai ancora la stessa quantità di cambi di rottura? – JRoughan

risposta

7

Nel tuo esempio non hai un BindingSource.

è necessario modificare in questo modo per utilizzare un BindingSource

var bs = new BindingSource(); 
    Foo foo1 = new Foo("bar1"); 
    fooList.Add(foo1); 

    bs.DataSource = fooList; //<-- point of interrest 

    //Bind fooList to the listBox 
    listBox1.DataSource = bs; //<-- notes it takes the entire bindingSource 

Modifica

essere consapevoli del fatto che (come è stato sottolineato nei commenti) - il BindingSource non funziona con INotifyPropertyChanged

+0

Questo funziona. Sfortunatamente, il contenuto ListBox non viene aggiornato quando la proprietà Bar di un membro fooList viene aggiornata altrove. C'è qualcuno che è infastidito dallo stesso problema qui: http://social.msdn.microsoft.it/Forum/it-US/netfxbcl/thread/f54c125f-6f53-4446-9088-a193f6474059 – Larry

+0

@Laurent buon punto. Non lo sapevo. Risposta modificata –

+0

Impressionante, funziona alla grande. – Michael

5

Prova

listBox1.DataSource = new BindingList<Foo>(fooList); 

poi

private void button1_Click(object sender, EventArgs e) 
{ 
    Foo foo2 = new Foo("bar2"); 
    (listBox1.DataSource as BindingList<Foo>).Add(foo2); 
} 

Questo aggiornerà fooList senza dover cambiare il suo tipo di originale. Inoltre, si aggiornerà il ListBox quando si cambia il membro bar come fooList[1].Bar = "Hello";

Tuttavia, sarà necessario impostare la proprietà DisplayMember della ListBox a "Bar", o per mantenere l'override .ToString() come è nella definizione della classe Foo.

Al fine di evitare di dover lanciare ogni volta, vi suggerisco di utilizzare una variabile BindingList allo stesso livello come la tua definizione di listino:

private List<Foo> fooList; 
private BindingList<Foo> fooListUI; 

fooListUI = new BindingList<Foo>(fooList); 
listBox1.DataSource = fooListUI; 

e nel pulsante:

Foo foo2 = new Foo("bar2"); 
fooListUI.Add(foo2); 
+0

Grazie per la soluzione, ma ho trovato la soluzione di Jens Kloster un po 'più elegante :) – Michael

+1

Lo rispetto! :-) – Larry