我需要在Silverlight 5中使用ObservableCollection的线程安全(并发)版本。由于SL5中缺少多线程支持,我很难找到创建一个版本的方法(没有ReaderWriterLock,没有Collections.Concurrent说话等等)。
我需要该集合在由另一个线程更新时支持UI绑定。当进程在后台运行时,我将所有更新分发到UI线程是不可接受的。理想情况下,后台进程可以根据需要自由更新集合,并且UI会在发生更改时接收通知。这可以通过.NET 4实现,我已经找到了为WPF实现这一目标的方法,但对SL来说却没有。我不能使用WPF示例,因为它们依赖于在SL5中不存在AFAIK的ReaderWriterLock。
赞赏任何方向和/或例子。
更新
在Silverlight中使用(必需)异步通信模式之后,“回调”方法或处理程序在不同的线程上运行。使用TPL(正如我们所做),这是任务的延续。
因为此代码在不同的线程上运行,所以任何影响ObservableCollection的语句都必须编组回UI线程。这意味着流程逻辑和时间现在正在消耗UI线程的资源。
.NET中并发集合的要点是允许生产者和使用者在不同的线程中运行,同时无缝地使用集合中的共享数据。 SL客户端应用程序中的“生产者”将是异步回调或任务延续,“消费者”是绑定到集合的UI。
答案 0 :(得分:4)
我也反复遇到这个问题,这让我走上你正在看的同一条路。有一个图书馆帮助我完成了这项任务:
我使用TinyReaderWriterLock实现了我自己的ConcurrentObservableCollection并实现了IList,INotifyCollectionChanged,INotifyPropertyChanged
我以此博客文章为出发点。 http://www.deanchalk.me.uk/post/Thread-Safe-Dispatcher-Safe-Observable-Collection-for-WPF.aspx
在我的版本中,我允许所有调用在调用线程上执行,并且只将INotifyCollectionChanged和INotifyPropertyChanged调用封送回UI线程,如下所示:
public void Add(T item)
{
mSyncLock.LockForWriting();
innerCollection.Add(item);
mSyncLock.ReleaseForWriting();
var index = IndexOf(item);
OnNotifyPropertyChanged(COUNT_PROPERTY);
OnNotifyPropertyChanged(INDEXER_PROPERTY);
OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, item, index); // This is an overload of OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
}
,其中
protected virtual void OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged == null) return;
ThreadSafeInvoke(() => CollectionChanged(this, e));
}
和
private static void ThreadSafeInvoke(Action action)
{
if (Deployment.Current.Dispatcher.CheckAccess())
{
action.Invoke();
}
else
{
Deployment.Current.Dispatcher.BeginInvoke(action);
}
}
这对我来说效果很好。锁定涉及小的性能损失,但对于大多数用途来说并不重要。