将列表绑定到数据源

Posted

技术标签:

【中文标题】将列表绑定到数据源【英文标题】:Bind List to DataSource 【发布时间】:2013-02-15 00:32:48 【问题描述】:

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

如果我用BindingList&lt;Foo&gt; fooList = new BindingList&lt;Foo&gt;(); 替换List&lt;Foo&gt; fooList = new List&lt;Foo&gt;();,那么它就可以工作。但我不想改变原来的傻瓜类型。我想要这样的工作:listBox1.DataSource = new BindingList&lt;Foo&gt;(fooList);

编辑:另外,我刚刚从 Ilia Jerebtsov 那里读到 List<T> vs BindingList<T> Advantages/DisAdvantages:“当您将 Bi​​ndingSource 的 DataSource 设置为 List 时,它会在内部创建一个 BindingList 来包装您的列表”。我认为我的示例只是表明这是不正确的:我的 List 似乎没有在内部包装到 BindingList。

【问题讨论】:

List 不会引发任何事件让观察者知道何时更新。观察者是 UI 组件还是充当包装器的另一个列表并不重要。为什么在绑定时反对更改为 BindingList 是您需要做的? 我不想将 List 更改为 BindingList,因为它已经在项目中的任何地方用作 List。我将不得不替换每个方法签名,我想避免修改已经稳定的内容。 如果将返回类型更改为 IList 会怎样?您仍然有相同数量的重大更改吗? 【参考方案1】:

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

编辑

请注意(正如 cmets 中指出的那样)- bindingsource 不适用于 INotifyPropertyChanged

【讨论】:

这行得通。不幸的是,当 fooList 成员的 Bar 属性在别处更新时,ListBox 内容不会更新。这里有人对同样的问题感到恼火:social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/…【参考方案2】:

试试

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"; 之类的 Bar 成员时,它会更新 ListBox

但是,您必须将 ListBox 的 DisplayMember 属性设置为“Bar”,以保持 .ToString() 覆盖与 Foo 类定义中的一样。

为了避免每次都强制转换,我建议您使用与您的 List 定义处于同一级别的 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);

【讨论】:

感谢您的解决方案,但我发现 Jens Kloster 的解决方案更加优雅 :)

以上是关于将列表绑定到数据源的主要内容,如果未能解决你的问题,请参考以下文章

将多个类的数据绑定到单个列表视图/xamarin 表单

将代码数据绑定到 XAML 透视列表框

将数据表绑定到复选框列表

如何将数据绑定到 Jquery Mobile 列表视图

将数据绑定到 ListBox 并将列表发布到数据库 mvc5

将对象列表数据绑定到 WinForms DataGridView,但不显示某些公共属性