在单独的线程中更新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 OnCollectionChanged
exception。 我们正在使用此解决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,竖起大拇指。 只要不尝试添加或删除集合本身的项目,就可以在后台线程中尽可能多地更新项目。