WPF:尽管使用了 Dispatcher.BeginInvoke,但访问绑定的 ObservableCollection 仍失败
我有以下内容:
public ICollectionView Children
{
get
{
// Determining if the object has children may be time-consuming because of network timeouts.
// Put that in a separate thread and only show the expander (+ sign) if and when children were found
ThreadPool.QueueUserWorkItem(delegate
{
if (_objectBase.HasChildren)
{
// We cannot add to a bound variable in a non-UI thread. Queue the add operation up in the UI dispatcher.
// Only add if count is (still!) zero.
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
if (_children.Count == 0)
{
_children.Add(DummyChild);
HasDummyChild = true;
}
}),
System.Windows.Threading.DispatcherPriority.DataBind);
}
});
return _childrenView;
}
}
它工作得很好:HasChildren 在后台线程中运行,该线程使用调度程序将其结果插入到用于绑定到 UI 的变量中。
注意:_childrenView 设置为:
_childrenView = (ListCollectionView) CollectionViewSource.GetDefaultView(_children);
问题:
如果我从另一个 ThreadPool 线程调用 Children 属性,则会在异常文本行中收到 NotSupportedException
_children.Add(DummyChild);
:“这种类型的 CollectionView 不支持对其 SourceCollection 进行更改来自与 Dispatcher 线程不同的线程。”
为什么?我已经验证该代码是从 Dispatcher 线程执行的。
I have the following:
public ICollectionView Children
{
get
{
// Determining if the object has children may be time-consuming because of network timeouts.
// Put that in a separate thread and only show the expander (+ sign) if and when children were found
ThreadPool.QueueUserWorkItem(delegate
{
if (_objectBase.HasChildren)
{
// We cannot add to a bound variable in a non-UI thread. Queue the add operation up in the UI dispatcher.
// Only add if count is (still!) zero.
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
if (_children.Count == 0)
{
_children.Add(DummyChild);
HasDummyChild = true;
}
}),
System.Windows.Threading.DispatcherPriority.DataBind);
}
});
return _childrenView;
}
}
It works great: HasChildren is run in a background thread which uses the dispatcher to insert its result into the variable used for the binding to the UI.
Note: _childrenView is set to this:
_childrenView = (ListCollectionView) CollectionViewSource.GetDefaultView(_children);
Problem:
If I call the Children property from another ThreadPool thread, I get a NotSupportedException in the line
_children.Add(DummyChild);
Exception text: "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread."
Why? I have verified that that code is executed from the Dispatcher thread.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我们自己就遇到过这个问题。问题有两个:
1- 确保对 SourceCollection 的任何更改都在主线程上(您已经完成了)。
2-确保 CollectionView 的创建也在主线程上(如果它是在不同的线程上创建的,例如响应事件处理程序,则通常不会出现这种情况)。 CollectionView 期望修改发生在“它的”线程上,并且“它的”线程是“UI”线程。
We've run into this problem before ourselves. The issue is twofold:
1- Make sure that any changes to the SourceCollection are on the main thread (you've done that).
2- Make sure that the creation of the CollectionView was also on the main thread (if it were created on a different thread, say in response to an event handler, this will not usually be the case). The CollectionView expects modifications to be on "its" thread, AND that "its" thread is the "UI" thread.