绑定列表到数据源

问题描述:

我希望能够将列表绑定到列表框数据源,并且当列表被修改时,列表框的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

您的示例中没有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

尝试

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