ObservableCollection 和 BindingList 的区别

Posted

技术标签:

【中文标题】ObservableCollection 和 BindingList 的区别【英文标题】:Difference between ObservableCollection and BindingList 【发布时间】:2011-05-16 03:23:09 【问题描述】:

我想知道ObservableCollectionBindingList 之间的区别,因为我已经使用两者来通知 Source 中的任何添加/删除更改,但实际上我不知道何时更喜欢其中一个。

为什么我会选择以下其中之一?

ObservableCollection<Employee> lstEmp = new ObservableCollection<Employee>();

BindingList<Employee> lstEmp = new BindingList<Employee>();

【问题讨论】:

【参考方案1】:

ObservableCollection 可以像任何集合一样从 UI 更新。真正的区别相当简单:

ObservableCollection&lt;T&gt; 实现了INotifyCollectionChanged,它在集合更改时提供通知(你猜对了^^) 它允许绑定引擎在 ObservableCollection 更新时更新 UI。

但是,BindingList&lt;T&gt; 实现了IBindingList

IBindingList 提供有关集合更改的通知,但不仅如此。它提供了一整套功能,UI 可以使用这些功能来提供比仅根据更改更新 UI 更多的东西,例如:

排序 正在搜索 通过工厂添加(AddNew 成员函数)。 只读列表(CanEdit 属性)

ObservableCollection&lt;T&gt;没有所有这些功能

另一个区别是BindingList 在其项目实现INotifyPropertyChanged 时中继项目更改通知。如果一个项目引发PropertyChanged 事件,BindingList 将接收它并引发ListChangedEventListChangedType.ItemChangedOldIndex=NewIndex(如果项目被替换,OldIndex=-1)。 ObservableCollection 不转发项目通知。

请注意,在 Silverlight 中,BindingList 不可用:但是您可以使用 ObservableCollections 和 ICollectionView(如果我没记错的话,还可以使用 IPagedCollectionView)。

【讨论】:

另一个要考虑的是性能,请参阅:themissingdocs.net/wordpress/?p=465 谢谢,我不知道 BindingList 的实际实现。我倾向于使用 ObservableCollection 和 ICollectionView 虽然此答案中的信息是正确的,但任何 WPF 用户都应注意:BindingList 未实现 INotifyCollectionChanged,如果绑定到控件的 ItemsSource 属性,则会导致内存泄漏。 ObservableCollection 确实实现了接口,不会导致任何此类泄漏。 如果 BindingList 实现了排序,那为什么不能对绑定到 BindingList 的网格进行排序呢? BindingList 过时了吗?【参考方案2】:

实际区别是BindingList是针对WinForms的,而ObservableCollection是针对WPF的。

从 WPF 的角度来看,BindingList 没有得到适当的支持,除非你真的不得不这样做,否则你永远不会真正在 WPF 项目中使用它。

【讨论】:

有趣。作为 Silverlight 开发人员,我不知道这一点。谢谢。如果你想要排序和过滤,ICollectionView 实现是你的朋友^^ 为什么“不支持”? ViewManager(内部)在 PresentationFramework 程序集中并支持它。例如,将其绑定到 ItemsControl 并遵守更改通知(即添加和删除项目)。如果它是特定于 WinForms 的,不应该更好地放在 Forms 命名空间中吗? 同意 David,它位于 System.Collections 命名空间中,因此 WPF 应该完全支持它。 WPF 只是一种不同的 UI 布局方式。 也同意 David,我在 WPF 中经常使用 BindingList,因为 ObservableCollection 不会从其项目中弹出属性更改通知。 举个“不支持”的例子:我刚刚在我的 WPF 应用程序中发现了一个内存泄漏,这是由于一些 BindingLists 没有实现 INotifyCollectionChanged【参考方案3】:

已接受的答案已经提到了最重要的区别,例如有关所包含元素的功能和更改通知,但还有更多,也值得一提:

性能

当调用AddNew 时,BindingList&lt;T&gt; 通过IndexOf 查找来搜索添加的项目。如果T 实现INotifyPropertyChanged,则更改元素的索引也会被IndexOf 搜索(尽管只要同一个项目重复更改,就没有新的查找)。如果您在集合中存储数千个元素,那么ObservableCollection&lt;T&gt;(或具有 O(1) 查找成本的自定义 IBindingList 实现)可能更可取。

完整性

IBindingList 接口是一个巨大的接口(可能不是最简洁的设计),它允许实现者只实现其功能的一个子集。例如,AllowNewSupportsSortingSupportsSearching 属性分别表示是否可以使用 AddNewApplySortFind 方法。 BindingList&lt;T&gt; 本身不支持排序,这常常让人们感到惊讶。实际上它提供了一些虚拟方法让派生类添加缺少的功能。 DataView 类是完整的 IBindingList 实现的示例;但是,它首先不适用于类型化集合。而 WinForms 中的 BindingSource 类是一个混合示例:如果它包装了另一个支持排序的 IBindingList 实现,则它支持排序。

ObservableCollection&lt;T&gt; 已经是INotifyCollectionChanged 接口的完整实现(它只有一个事件)。它也有虚拟成员,但ObservableCollection&lt;T&gt; 的派生原因通常与其基类Collection&lt;T&gt; 相同:用于自定义添加/删除项目(例如在数据模型集合中)而不是调整绑定功能。

复制与包装

ObservableCollection&lt;T&gt;BindingList&lt;T&gt; 都有一个构造函数,它接受一个已经存在的列表。尽管它们在被另一个集合实例化时表现不同:

BindingList&lt;T&gt; 充当提供列表的可观察包装器,对BindingList&lt;T&gt; 执行的更改也将反映在基础集合中。 另一方面,ObservableCollection&lt;T&gt; 将一个新的List&lt;T&gt; 实例传递给基本Collection&lt;T&gt; 构造函数,并将原始集合的元素复制到这个新列表中。当然,如果T 是引用类型,则元素上的更改将从原始集合中可见,但集合本身不会更新。

【讨论】:

良好而彻底的答案。需要注意的是:BindingList&lt;T&gt; 具有性能损失只是因为它正在做一些 ObservableCollection&lt;T&gt; 不支持的额外功能。使后者实现内部项目的更改通知并给出changedItem的索引,它会产生相同的结果。我只是认为在这种情况下返回索引是BindingList&lt;T&gt; 部分的错误。他们本可以只返回更改的项目,并留给客户决定是否需要项目索引(客户可以自己做一个list.IndexOf 关于包装与复制行为差异的要点。我一直认为最好将它们命名为 ObservableList(就像任何其他新的 List 一样)和 BindingCollection(作为 Collection、ReadOnlyCollection 等其他集合的包装器) )。 感谢您的意见。实际上,自从发布此答案以来,我免费提供了我的库,其中包含一个没有性能损失的 FastBindingList,以及一个统一两个世界的 SortableBindingList 和一个 ObservableBindingList。 GitHub:github.com/koszeggy/KGySoft.CoreLibraries 我看了看,FastBindingCollection。因此,您正在预先构建索引图。所以权衡在别处:) 如果您调用字典初始化权衡,那么是的,它是。 :) 它具有一次性 O(n) 成本(当您将已经存在的集合传递给 ctor 时),以及添加/删除项目时几乎 O(1) 的维护成本。【参考方案4】:

ObservableCollectionBindingList 之间的另一个巨大差异很方便,并且可以成为该主题的出价决策因素:

BindingList列表更改处理程序:

ObservableCollection收藏变更:

以上简要说明:如果在BindingList 中更改项目的属性,ListChanged 事件将为您提供完整的详细信息 属性(在 PropertyDescriptor 中)和ObservableCollection 不会给你那个。实际上 ObservableCollection 不会引发属性的更改事件 在一个项目中更改。

以上结论是关于在模型类中实现的INotifyPropertyChanged。默认情况下,如果项目中的属性发生更改,则 none 会引发 changed 事件。

【讨论】:

我认为这(PropertyDescriptor)可能是内存泄漏的来源【参考方案5】:

两者都有优点和缺点,需要一些时间才能发现。

我在使用 BindingList 时遇到了一些问题,因为更改通知事件仅发生在 一个项目被删除并且只提供一个索引(这意味着您必须跟踪哪个对象在哪个位置如果您实施了一些删除后机制)。另一方面,ObservableCollection 为您提供已删除项目的列表。

BindingList 有一个方便的 AddNew() 方法,它允许派生类实现工厂模式,例如使用取决于父集合的值初始化新项目(例如,如果集合包含子项目,则为父集合的外键)。

还请注意,使用(Entity Framework 中的 ToBindingList 扩展)从 ObservableCollection 获取 BindingList 非常容易,并且返回的(派生的)BindingList 实现了普通香草中缺乏的功能,例如排序。

【讨论】:

以上是关于ObservableCollection 和 BindingList 的区别的主要内容,如果未能解决你的问题,请参考以下文章

ObservableCollection 和 BindingList 的区别

INotifyPropertyChanged 和 ObservableCollection WPF

ObservableCollection和List的区别总结

ObservableCollection和List的区别总结

WPF/MVVM中ObservableCollection的双向绑定和过滤

线程化和创建 ObservableCollection