实现INotifyCollectionChanged的异步,线程安全集合

时间:2012-03-13 20:34:00

标签: c# silverlight task-parallel-library

我使用的是Silverlight 5.0,需要实现IList<T>和IList。我的集合将用于不断地从其内部集合中添加和删除项目,并且UI将具有绑定到集合的元素。出于性能原因,我不希望每次集合更改时都会呈现UI,因为我希望对集合进行“组”更改,然后引发集合更改事件。我还希望能够使用Task.Factory方法来保持所有异步。有没有人见过如何实现这个目标的好例子?

2 个答案:

答案 0 :(得分:0)

线程安全,可观察的集合在设计上存在问题。例如,如果更改集合并引发事件,则在处理该事件时,可以在另一个线程上更改集合。结果,刚刚告知添加项目的处理程序可能已经过时(该项目可能已经消失)。

或者,您是否考虑过在收集更改时使用immutable collection的事件?它本质上是线程安全的,如果你正确应用它就不会遇到上述设计问题。它可能不符合您对此应用的要求 - 从问题中很难说清楚。

答案 1 :(得分:0)

我建议的方法是为可能需要更新UI的集合的不同方面提供各种标志。如果集合中的某些内容发生更改且未设置特定标志,请将其设置并在提供的控件和委托上使用Control.BeginInvoke(使用Interlocked或锁定以确保标记测试和设置以线程安全的方式完成)。 UI更新方法应该在执行更新之前测试并清除相应的标志;如果执行了任何更新,该方法应循环并重新测试所有标志,直到完成而不必执行任何更新。

使用这种方法,应该能够避免通过BeginUpdate排队过多的待处理操作。可能存在一些冗余更新,但通常不会太多。在某些情况下,让控件的代码限制它每秒执行的更新次数可能会有所帮助;如果更新例程将循环太多次,则启动计时器并禁用更新,直到计时器到期为止。如果计时器到期并需要更新,请执行更新并重新启动计时器;如果它过期并且不需要更新,则终止计时器。

尝试对集合中的每一个更改都反映在“更新”事件中,这往往会适得其反。只需确保显示的最后一次更新完全发生在最后一次更改集合之后。