Получение исключений доступа к потокам в OnCollectionChanged после обновления создателей
В моей программе у меня есть абстрактный класс ObservableKeyedCollection<TKey, TItem>
что наследует от KeyedCollection<TKey, TItem>
а также реализует INotifyCollectionChanged
,
Реализация этого абстрактного класса связана с ListBox
, В этом ListBox
Я редактирую элементы по двойному щелчку, и после принятия удаляю старый экземпляр отредактированного элемента из этого ObservableKeyedCollection<TKey, TItem>
реализации, и добавьте новый экземпляр, который был изменен.
Все работало хорошо до Windows 10 Creators Update (1703, номер сборки 15063.250). С момента обновления, ObservableKeyedCollection<TKey, TItem>
начал бросать InvalidOperationException
s со следующим сообщением:
Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им.
Я не использую никаких асинхронных операций в этой области кода.
Трассировка всего стека будет слишком длинной, но вот верхняя часть, начинающаяся с OnCollectionChanged
:
в System.Windows.Threading.Dispatcher.VerifyAccess() в System.Windows.Threading.DispatcherObject.VerifyAccess() в System.Windows.DependencyObject.GetValue(DependencyProperty dp) в System.Windows.Controls.Primitives.Selector.ject en элемент) в System.Windows.Controls.Primitives.Selector.ItemSetIsSelected(информация об ItemInfo, логическое значение) в System.Windows.Controls.Primitives.Selector.SelectionChanger.CreateDeltaSelectionChange(List'1, невыбранные элементы System, List'1, выбранные элементы Windows).Controls.Primitives.Selector.SelectionChanger.End() в System.Windows.Controls.Primitives.Selector.RemoveFromSelection(NotifyCollectionChangedEventArgs e) в System.Windows.Controls.Primitives.Selector.OnItemsCindows.vent.ItemsControl.OnItemCollectionChanged2(Отправитель объекта, NotifyCollectionChangedEventArgs e) в System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Отправитель объекта, NotifyCollectionChang eEventArgs e) в System.Windows.Data.CollectionView.OnCollectionChanged(аргументы NotifyCollectionChangedEventArgs) в System.Windows.Controls.ItemCollection.OnViewCollectionChanged(отправитель объекта, NotifyCollectionChangedEventArgs e) в объекте класса. EventArgs e, тип managerType) в System.Windows.WeakEventManager.DeliverEventToList (отправитель объекта, аргументы EventArgs, список ListenerList) в System.Windows.WeakEventManager.DeliverEvent (отправитель объекта, аргументы EventArgs) в System.Collections.Specialized.hol отправитель объекта, NotifyCollectionChangedEventArgs арг) при System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs арг) в System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs арг, Int32, Int32 adjustedOldIndex adjustedNewIndex) в System.Windows.Data.ListCollectionView.ProcessCollectionChanged(Поставить в известность CollectionChangedEventArgs args) в System.Windows.Data.CollectionView.OnCollectionChanged(объект-отправитель, NotifyCollectionChangedEventArgs args) в Tether cs, номер строки: 68 в TethedSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) в [...]
Изменить 1:
Здесь приведен фрагмент кода, который работал нормально до обновления Creators (переопределение KeyedCollection<TKey, TItem>.RemoveItem(int index)
):
protected override void RemoveItem(int index)
{
TItem item = this[index];
base.RemoveItem(index);
if (deferNotifyCollectionChanged) return;
if (item is IList) {
// Listeners do not support multiple item changes, and our item happens to be an IList, so we must raise NotifyCollectionChangedAction.Reset.
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
} else {
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
}
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
}
Кажется, проблема возникает, только если я призываю OnCollectionChanged
с NotifyCollectionChangedAction.Remove
действие. Заменить его на NotifyCollectionChangedAction.Reset
кажется, чтобы предотвратить исключение:
protected override void RemoveItem(int index)
{
TItem item = this[index];
base.RemoveItem(index);
if (deferNotifyCollectionChanged) return;
// No exception thrown so far if I stick to NotifyCollectionChangedAction.Reset:
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
}
Я пытался решить проблему с Dispatcher
как видно здесь: /questions/25769821/obnovlenie-donet-45-itemscontrol-nesovmestim-s-istochnikom-svoih-elementov/25769835#25769835 но, хотя мой диспетчер не является нулевым, его CheckAccess()
оценивается как истина, и я продолжаю получать одно и то же исключение при NotifyCollectionChangedEventHandler.Invoke()
,
Ваши мысли и помощь очень ценятся.
1 ответ
У меня была похожая проблема, а также после обновления создателей Win 10.
Этот класс-оболочка, использующий BindingOperations.EnableCollectionSynchronization, работал для меня:
public class SynchronizedObservableCollection<T> : ObservableCollection<T>
{
private readonly object _lockObject = new object();
public SynchronizedObservableCollection()
{
Init();
}
public SynchronizedObservableCollection(List<T> list) : base(list)
{
Init();
}
public SynchronizedObservableCollection(IEnumerable<T> collection) : base(collection)
{
Init();
}
private void Init()
{
BindingOperations.EnableCollectionSynchronization(this, _lockObject);
}
}