我在哪里可以获得线程安全的 CollectionView?
在后台线程上更新业务对象集合时,我收到以下错误消息:
这种类型的 CollectionView 不支持从与 Dispatcher 线程不同的线程更改其 SourceCollection。
好吧,这是有道理的。但它也引出了一个问题,什么版本的 CollectionView 确实支持多线程以及如何让我的对象使用它?
When updating a collection of business objects on a background thread I get this error message:
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
Ok, that makes sense. But it also begs the question, what version of CollectionView does support multiple threads and how do I make my objects use it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
使用:
Use:
以下是 Jonathan 发现的实施改进。首先,它在与其关联的调度程序上运行每个事件处理程序,而不是假设它们都在同一个 (UI) 调度程序上。其次,它使用 BeginInvoke 允许在我们等待调度程序可用时继续处理。在后台线程进行大量更新并在每个更新之间进行处理的情况下,这使得解决方案速度更快。也许更重要的是,它克服了等待 Invoke 时阻塞引起的问题(例如,在将 WCF 与 ConcurrencyMode.Single 一起使用时可能会发生死锁)。
因为我们使用的是 BeginInvoke,所以通知的更改可能会在调用处理程序之前被撤消。这通常会导致“索引超出范围”。当根据列表的新(更改)状态检查事件参数时抛出异常。为了避免这种情况,所有延迟事件都被替换为重置事件。在某些情况下,这可能会导致过度重绘。
The following is an improvement on the implementation found by Jonathan. Firstly it runs each event handler on the dispatcher associated with it rather than assuming that they are all on the same (UI) dispatcher. Secondly it uses BeginInvoke to allow processing to continue while we wait for the dispatcher to become available. This makes the solution much faster in situations where the background thread is doing lots of updates with processing between each one. Perhaps more importantly it overcomes problems caused by blocking while waiting for the Invoke (deadlocks can occur for example when using WCF with ConcurrencyMode.Single).
Because we are using BeginInvoke, it is possible that the change being notified is undone before the handler is called. This would typically result in an "Index was out of range." exception being thrown when the event arguments are checked against the new (altered) state of the list. In order to avoid this, all delayed events are replaced with Reset events. This could cause excessive redrawing in some cases.
Bea Stollnitz 的这篇文章解释了错误消息以及原因它的措辞就是这样。
编辑:来自 Bea 的博客
This post by Bea Stollnitz explains that error message and why it's worded the way it is.
EDIT: From Bea's blog
找到了一个。
http://www.julmar.com/blog/mark/2009 /04/01/AddingToAnObservableCollectionFromABackgroundThread.aspx
Found one.
http://www.julmar.com/blog/mark/2009/04/01/AddingToAnObservableCollectionFromABackgroundThread.aspx
您还可以查看:
BindingOperations.EnableCollectionSynchronization
。请参阅升级到 .NET 4.5 : ItemsControl 与其项目源不一致
You can also look at:
BindingOperations.EnableCollectionSynchronization
.See Upgrading to .NET 4.5: An ItemsControl is inconsistent with its items source
抱歉,无法添加评论,但这一切都是错误的。
ObservableCollection 不是线程安全的。不仅因为这个调度程序问题,而且它根本不是线程安全的(来自msdn):
看这里 http://msdn.microsoft.com /en-us/library/ms668604(v=vs.110).aspx
使用“重置”操作调用 BeginInvoke 时也存在问题。 “重置”是处理程序应该查看集合本身的唯一操作。如果您开始调用“重置”,然后立即开始调用几个“添加”操作,则处理程序将接受具有已更新集合的“重置”,而下一个“添加”将造成混乱。
这是我的有效实现。实际上,我正在考虑完全删除 BeginInvoke:
快速执行和线程安全的可观察集合
Sorry, can't add a comment but all this is wrong.
ObservableCollection is not thread safe. Not only because of this dispatcher issues, but it's not thread safe at all (from msdn):
Look here http://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx
There's also a problem when calling BeginInvoke with a "Reset" action. "Reset" is the only action where handler should look at the collection itself. If you BeginInvoke a "Reset" and then immediately BeginInvoke a couple of "Add" actions than handler will accept a "Reset" with already updated collection and next "Add"'s will create a mess.
Here's my implementation which works. Actually I'm thinking of removing BeginInvoke at all:
Fast performing and thread safe observable collection
您可以让 wpf 通过启用集合同步来管理对集合的跨线程更改,如下所示:
这告诉 WPF 可以在 UI 线程之外修改集合,因此它知道必须将任何 UI 更改封送回适当的线程。
如果您没有锁对象,还有一个重载可以提供同步回调。
You can get wpf to manage cross thread changes to a collection by enabling collection synchronization like so:
This tells WPF that the collection may be modified off the UI thread so it knows it has to marshal any UI changes back to the appropriate thread.
There is also an overload to provide a synchronization callback if you don't have a lock object.
如果您想定期更新 WPF UI 控件并同时使用 UI,则可以使用 DispatcherTimer。
XAML
C#
If you want to update WPF UI Control periodically and at the same time use UI you can use DispatcherTimer.
XAML
C#
试试这个:
Try This:
都没有,只需使用 Dispatcher.BeginInvoke
None of them, just use Dispatcher.BeginInvoke
这是我在谷歌搜索和轻微修改后制作的 VB 版本。对我有用。
Here's a VB version I made after some googling and slight mods. Works for me.
VB版本中的小错误。只需替换:
由
Small mistake in the VB version. Just replace :
By