【发布时间】:2019-04-12 22:09:27
【问题描述】:
我有一个应用程序,其中项目从多个线程添加到集合中。 随机我得到一个
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread. at System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
现在集合是在一个类中创建的,类本身是在多个线程上创建的。
这是一个类示例
public class Example
{
public Example()
{
BindingOperations.EnableCollectionSynchronization(collection, COLLECTION_LOCK);
var defaultView = CollectionViewSource.GetDefaultView(collection);
defaultView.SortDescriptions.Add(new SortDescription("SomeProperty", ListSortDirection.Ascending));
if (defaultView is ICollectionViewLiveShaping liveShaping)
liveShaping.IsLiveSorting = true;
}
private readonly object COLLECTION_LOCK = new object();
private readonly ObservableCollection<object> collection = new ObservableCollection<object>();
public ObservableCollection<object> Collection
{
get
{
return collection;
}
}
private void AddItem(object item)
{
lock(COLLECTION_LOCK)
{
if(!Collection.Contains(item))
{
Collection.Add(item);
}
}
}
private void RemoveItem(object item)
{
lock (COLLECTION_LOCK)
{
if (Collection.Contains(item))
{
Collection.Remove(item);
}
}
}
}
我正在使用 BindingOperations.EnableCollectionSynchronization 来允许跨线程操作并始终使用指定的锁来修改集合。 错误仍然随机出现。
我也尝试在访问集合时使用 BindingOperations.AccessCollection,但错误仍然随机发生。
MS 文档指出 ObservableCollection 必须在 UI 线程上创建?有人可以确认是这样吗?
您还可以注意到我得到了默认的集合视图 CollectionViewSource.GetDefaultView(collection)
集合视图也是在同一线程和技术上创建的,因为我了解它的问题根源。
我试图通过创建数千个任务并修改集合而不发生错误来模拟从不同线程添加,但再次随机错误突然弹出,我测试了集合未绑定和绑定到 UI 的地方。
有什么想法吗?
堆栈跟踪
System.NotSupportedException: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
at System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection`1.RemoveItem(Int32 index)
at System.Collections.ObjectModel.Collection`1.Remove(T item)
at Manager.ViewModels.HostViewModelBase.RemoveUser(IUserMemberViewModel user)
集合视图标志是 System.Windows.Data.CollectionView.CollectionViewFlags.ShouldProcessCollectionChanged | System.Windows.Data.CollectionView.CollectionViewFlags.IsCurrentBeforeFirst | System.Windows.Data.CollectionView.CollectionViewFlags.IsCurrentAfterLast | System.Windows.Data.CollectionView.CollectionViewFlags.IsDynamic | System.Windows.Data.CollectionView.CollectionViewFlags.AllowsCrossThreadChanges | System.Windows.Data.CollectionView.CollectionViewFlags.CachedIsEmpty
并且 AllowsCrossThreadChanges 为真
【问题讨论】:
-
您应该使用
Dispatcher.Invoke来更新集合。您的问题与此 one 重复 -
Dispatcher.Invoke ?如果是这样,为什么有一个用于跨线程修改的 api?此外,进行修改或创建包含集合的类的代码本身不知道 Dispatcher,我不想依赖它。
-
我曾经遇到过同样的问题,您不能从不同的线程更改集合。应该使用创建它的线程对其进行修改。
-
@NullReference 我有同样的问题不知道为什么?