创建者更新

时间:2017-05-07 15:11:47

标签: c# wpf inotifycollectionchanged cross-thread

在我的程序中,我有一个摘要类ObservableKeyedCollection<TKey, TItem>,它继承自KeyedCollection<TKey, TItem>并且还实现了INotifyCollectionChanged

此抽象类的实现绑定到ListBox。在这个ListBox中,我在双击时编辑项目,一旦接受,我将从此ObservableKeyedCollection<TKey, TItem>实现中删除已编辑项目的旧实例,并添加已修改的新实例。

在Windows 10 Creators Update(1703,内部版本号15063.250)之前,这一切都运行良好。自更新以来,ObservableKeyedCollection<TKey, TItem>开始向InvalidOperationException投掷以下消息:

  

调用线程无法访问此对象,因为另一个线程拥有它。

我不在代码的这个区域使用任何异步操作。

整个堆栈跟踪太长,但这里是以OnCollectionChanged开头的顶部:

  System.Windows.Threading.Dispatcher.VerifyAccess()上的

     在System.Windows.Threading.DispatcherObject.VerifyAccess()      在System.Windows.DependencyObject.GetValue(DependencyProperty dp)      在System.Windows.Controls.Primitives.Selector.GetIsSelected(DependencyObject元素)      在System.Windows.Controls.Primitives.Selector.ItemSetIsSelected(ItemInfo info,Boolean value)      在System.Windows.Controls.Primitives.Selector.SelectionChanger.CreateDeltaSelectionChange(List'1 unselectedItems,List'1 selectedItems)      在System.Windows.Controls.Primitives.Selector.SelectionChanger.End()      在System.Windows.Controls.Primitives.Selector.RemoveFromSelection(NotifyCollectionChangedEventArgs e)      在System.Windows.Controls.Primitives.Selector.OnItemsChanged(NotifyCollectionChangedEventArgs e)      在System.Windows.Controls.ItemsControl.OnItemCollectionChanged2(Object sender,NotifyCollectionChangedEventArgs e)      在System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender,NotifyCollectionChangedEventArgs e)      在System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)      在System.Windows.Controls.ItemCollection.OnViewCollectionChanged(Object sender,NotifyCollectionChangedEventArgs e)      在System.Windows.WeakEventManager.ListenerList'1.DeliverEvent(Object sender,EventArgs e,Type managerType)      在System.Windows.WeakEventManager.DeliverEventToList(Object sender,EventArgs args,ListenerList list)      在System.Windows.WeakEventManager.DeliverEvent(Object sender,EventArgs args)      在System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender,NotifyCollectionChangedEventArgs args)      在System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)      在System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args,Int32 adjustedOldIndex,Int32 adjustedNewIndex)      在System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)      在System.Windows.Data.CollectionView.OnCollectionChanged(Object sender,NotifyCollectionChangedEventArgs args)      at TetheredSun.ObservableKeyedCollection'2.OnCollectionChanged(NotifyCollectionChangedEventArgs e)at e:\ Phil \Programozás\ Modulok \ TetheredSun.1.0 \ TetheredSun \ ObservableKeyedCollection.cs,行号:68      at [...]

的TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index)

修改1:

以下是在创作者更新(覆盖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来解决这个问题,如下所示:https://stackoverflow.com/a/22026686/2659699但是虽然我的调度程序不为null,但它的CheckAccess()计算结果为true,而且我一直都是这样的NotifyCollectionChangedEventHandler.Invoke()上的例外情况。

非常感谢您的想法和帮助。

1 个答案:

答案 0 :(得分: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);
    }
}