2013-02-28 12 views
7

Chcę móc powiązać listę ze źródłem danych listbox, a kiedy lista zostanie zmodyfikowana, interfejs listy listbox zostanie automatycznie zaktualizowany. (Winformy nie ASP). Oto przykład:Lista powiązań do źródła danych

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_; 
    } 
} 

Gdybym zastąpić List<Foo> fooList = new List<Foo>(); przez BindingList<Foo> fooList = new BindingList<Foo>(); to działa. Ale nie chcę zmieniać oryginalnego typu foolist. Chciałbym coś takiego pracy: listBox1.DataSource = new BindingList<Foo>(fooList);

EDIT: Również Właśnie przeczytałem tutaj List<T> vs BindingList<T> Advantages/DisAdvantages z Ilia Jerebtsov: „Po ustawieniu DataSource BindingSource użytkownika do listy <>, to wewnętrznie tworzy BindingList zawijać liście”. Myślę, że moja próbka demonstruje, że to nie jest prawda: moja lista <> nie jest wewnętrznie zapakowana w BindingList <>.

+0

Lista <> nie powoduje żadnych zdarzeń dla obserwatorów, aby wiedzieć, kiedy dokonać aktualizacji. Nie ma znaczenia, czy obserwator jest składnikiem interfejsu użytkownika, czy inną listą działającą jako opakowanie. Dlaczego sprzeciw wobec zmiany na Listę wiążącą podczas wiązania jest tym, co musisz zrobić? – JRoughan

+0

Nie chcę zmieniać listy na BindingList, ponieważ jest już używana jako lista wszędzie w projekcie. Będę musiał wymienić wszystkie podpisy metod, chcę uniknąć modyfikowania tego, co jest już stabilne. – Michael

+0

Co się stanie, jeśli zmienisz typ zwrotu na IList ? Czy nadal masz taką samą ilość przełomowych zmian? – JRoughan

Odpowiedz

7

Nie masz w swoim przykładzie BindingSource.

trzeba zmodyfikować go tak, aby użyć 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 

Edycja

Należy pamiętać, że (jak wskazano w komentarzach) - w BindingSource nie działa z INotifyPropertyChanged

+0

To działa. Niestety zawartość ListBox nie jest aktualizowana, gdy właściwość Bar członka fooList jest aktualizowana w innym miejscu. Jest tutaj ktoś, kto jest zirytowany tym samym problemem: http://social.msdn.microsoft.com/Forums/pl-US/netfxbcl/thread/f54c125f-6f53-4446-9088-a193f6474059 – Larry

+0

@Laurent dobry punkt. Nie wiedziałem o tym. Edytowana odpowiedź –

+0

Awesome, działa świetnie. – Michael

5

Spróbuj

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

następnie

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

Spowoduje to aktualizację fooList bez konieczności zmiany jego oryginalny typ. Będzie również aktualizować ListBox po zmianie elementu bar Podoba fooList[1].Bar = "Hello";

jednak będzie trzeba ustawić właściwość ListBox do „Bar”, lubDisplayMember zachować .ToString (nadpisanie), jak jest w definicji klasy Foo.

W celu uniknięcia musiał rzucać za każdym razem, proponuję użyć zmiennej BindingList na tym samym poziomie jak definicji listy:

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

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

aw przycisku:

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

Dzięki za rozwiązanie, ale znalazłem rozwiązanie Jens Kloster nieco bardziej eleganckie :) – Michael

+1

Szanuję to! :-) – Larry

Powiązane problemy