在单独的线程中更新ObservableCollection

在WPF应用程序中,通过LINQ to SQL查询填充和更新ObservableCollection。 然后使用这个ObservableCollection中的值更新UI对象。

LINQ to SQL查询更新这个ObservableCollection的操作在单独的线程中执行是否可行?

如果是的话,在这种情况下,它会是这个ObservableCollection的同一个实例吗? (我的意思是,如果它不是从LINQ datacontext中获取值,也不是用于更新UI的值,那么我将无法更新UI)

使用内置的ObservableCollection<T>类,如果UI绑定到集合,则不能更改单独线程的内容,但会引发NotSupportedException (但可以更改集合项属性的通知)。 我写了一个AsyncObservableCollection<T>类来处理这种情况。 它通过调用UI同步上下文中的事件处理程序来工作

.Net 4.5在BindingOperations类中提供了一个解决scheme。

您现在可以使用BindingOperations.EnableCollectionSynchronization方法,如下所示:

 private readonly object _personCollectionLock; private ObservableCollection<Person> _personCollection; public ObservableCollection<Person> PersonCollection { get { return _personCollection; } set { _personCollection = value; BindingOperations.EnableCollectionSynchronization(_personCollection, _personCollectionLock); } 

我只是刚刚在我的开发环境中尝试过这一点,但是现在当我从后台线程更新集合时,一切似乎都正常工作。

有关此解决scheme的更深入的讨论: http : //10rem.net/blog/2012/01/16/wpf-45-observable-collection-cross-thread-change-notification

此方法的MSDN条目是: https : //msdn.microsoft.com/en-us/library/system.windows.data.bindingoperations.enablecollectionsynchronization(v = vs.110).aspx

在我们的应用程序中,我们有一个绑定到ObservableCollection的TreeView,我们经常在后台线程中更新,从存储中请求数据。 它完美的作品!

哎呦。 我被误解了=))

对,我们实际上是OnCollectionChanged ObservableCollection<T>并重写OnCollectionChanged方法以避免UI OnCollectionChangedexception。 我们正在使用此解决scheme :

 public class MTObservableCollection<T> : ObservableCollection<T> { public override event NotifyCollectionChangedEventHandler CollectionChanged; protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { var eh = CollectionChanged; if (eh != null) { Dispatcher dispatcher = (from NotifyCollectionChangedEventHandler nh in eh.GetInvocationList() let dpo = nh.Target as DispatcherObject where dpo != null select dpo.Dispatcher).FirstOrDefault(); if (dispatcher != null && dispatcher.CheckAccess() == false) { dispatcher.Invoke(DispatcherPriority.DataBind, (Action)(() => OnCollectionChanged(e))); } else { foreach (NotifyCollectionChangedEventHandler nh in eh.GetInvocationList()) nh.Invoke(this, e); } } } } 

没有这个覆盖,你会得到这样的例外

System.NotSupportedException:此types的CollectionView不支持从与分派器线程不同的线程更改其SourceCollection。

现在唯一的问题是select的项目位置,在某些情况下,如果从集合中删除当前选定的项目,TreeView将select移动到下一个项目(这会导致我们的应用程序中出现一些其他不必要的UI操作)。 但这是一个小问题。

试着在这里了解你的问题:

 情况1
 1. LINQ to SQL从数据库检索数据集并添加到ObservableCollection A.
 2.定期从数据库中检索更多数据并将其添加到A.旧数据从A中删除。

 情景2
 1. LINQ to SQL从数据库检索数据集并添加到ObservableCollection A.
 2.定期使用数据库中的新数据更新A中的数据(不添加/删除)。

情景1,你将不得不使用UI线程。 UI线程拥有ObservableCollection,如果你尝试在另一个线程中使用它,你会得到一个exception。

情景2,竖起大拇指。 只要不尝试添加或删除集合本身的项目,就可以在后台线程中尽可能多地更新项目。