У меня есть приложение, в котором элементы добавляются в коллекции из нескольких потоков.
Случайно я получаю
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 необходимо создавать в потоке пользовательского интерфейса? Кто-то может подтвердить, что это так?
Также вы можете заметить, что я получаю представление коллекции по умолчанию CollectionViewSource.GetDefaultView (collection)
Представление коллекции также создается в том же потоке и технически, как я понимаю, является источником проблемы.
Я пытался смоделировать добавление из разных потоков, создавая тысячи задач и изменяя коллекцию без ошибок, НО снова случайная ошибка появляется из ниоткуда, я проверял обе, где коллекция не была связана и связана с пользовательским интерфейсом.
Есть идеи?
трассировка стека
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 имеет значение true