Получение исключений доступа к потокам в OnCollectionChanged после обновления создателей

В моей программе у меня есть абстрактный класс ObservableKeyedCollection<TKey, TItem> что наследует от KeyedCollection<TKey, TItem> а также реализует INotifyCollectionChanged,

Реализация этого абстрактного класса связана с ListBox, В этом ListBoxЯ редактирую элементы по двойному щелчку, и после принятия удаляю старый экземпляр отредактированного элемента из этого ObservableKeyedCollection<TKey, TItem> реализации, и добавьте новый экземпляр, который был изменен.

Все работало хорошо до Windows 10 Creators Update (1703, номер сборки 15063.250). С момента обновления, ObservableKeyedCollection<TKey, TItem> начал бросать InvalidOperationExceptions со следующим сообщением:

Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им.

Я не использую никаких асинхронных операций в этой области кода.

Трассировка всего стека будет слишком длинной, но вот верхняя часть, начинающаяся с 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);
    }
}
Другие вопросы по тегам