2013-02-28 68 views
7

我希望能夠將列表綁定到列表框數據源,並且當列表被修改時,列表框的UI自動更新。 (Winforms不是ASP)。 下面是一個示例:綁定列表到數據源

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

如果我更換List<Foo> fooList = new List<Foo>();通過BindingList<Foo> fooList = new BindingList<Foo>();然後它工作。但我不想改變原來的傻子式。我想是這樣工作的:listBox1.DataSource = new BindingList<Foo>(fooList);

編輯:另外我剛剛讀到這裏List<T> vs BindingList<T> Advantages/DisAdvantages從伊利亞Jerebtsov:「當你設置一個的BindingSource的DataSource到一個列表<>,它在內部創建一個的BindingList包列表」。我認爲我的示例只是證明這不是真的:我的清單<>似乎沒有內部包裝到BindingList <>中。

+0

列表<>不會引發觀察員知道何時更新的任何事件。觀察者是一個UI組件還是充當包裝的另一個列表並不重要。爲什麼在綁定時反對更改爲綁定列表是您需要做的事情? – JRoughan 2013-02-28 18:20:18

+0

我不想將列表更改爲BindingList,因爲它已經在項目的任何地方用作列表。我將不得不更換每個方法簽名,我想避免修改已經穩定的內容。 – Michael 2013-02-28 18:26:17

+0

如果您將退貨類型更改爲IList ,該怎麼辦?你是否仍然有相同數量的重大變化? – JRoughan 2013-02-28 19:25:17

回答

7

您的示例中沒有BindingSource

您需要修改它這樣使用的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 

編輯

要知道,(如在評論中指出) - BindingSource的不INotifyPropertyChanged

工作
+0

這工作。不幸的是,當fooList成員的Bar屬性在其他地方更新時,ListBox內容不會更新。有一個人在這裏遇到同樣的問題:http://social.msdn.microsoft。com/Forums/en-US/netfxbcl/thread/f54c125f-6f53-4446-9088-a193f6474059 – Larry 2013-02-28 19:48:03

+0

@Laurent好點。我不知道。編輯答案 – 2013-02-28 19:51:07

+0

太棒了,效果很好。 – Michael 2013-02-28 21:33:17

5

嘗試

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

然後

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

這將更新fooList而無需改變其原來的類型。此外,當你改變杆件類似fooList[1].Bar = "Hello";

但是它會更新列表框,你將不得不設置列表框「酒吧」,DisplayMember屬性來保持的ToString()重寫爲是在Foo類定義中。

爲了避免有投每一次,我建議你在同級別使用的BindingList變量列表定義:

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

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

和按鈕:

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

感謝您的解決方案,但我發現Jens Kloster的解決方案更加優雅:) – Michael 2013-02-28 21:35:07

+1

我尊重這一點! :-) – Larry 2013-02-28 21:58:21