5

在我的程序中,我有一个抽象类ObservableKeyedCollection<TKey, TItem>,它继承自KeyedCollection<TKey, TItem>并实现INotifyCollectionChanged.

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

在 Windows 10 创意者更新(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.GetIsSelected(DependencyObject元素) 在 System.Windows.Controls.Primitives.Selector.SelectionChanger.CreateDeltaSelectionChange(List'1 unselectedItems, List'1 selectedItems) 在 System.Windows.Windows.Controls.Primitives.Selector.ItemSetIsSelected(ItemInfo info, Boolean value) .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) at System.Windows.WeakEventManager.ListenerList'1.DeliverEvent(Object sender, EventArgs e, Type managerType) at System.Windows.WeakEventManager.DeliverEventToList(Object sender, EventArgs args, ListenerList list) at System .Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args) at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender,NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32adjustedOldIndex, Int32adjustedNewIndex) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChangedargs ) 在 System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 在 TetheredSun.ObservableKeyedCollection'2.OnCollectionChanged(NotifyCollectionChangedEventArgs e) 在 e:\Phil\Programozás\Modulok\TetheredSun.1.0\TetheredSun\ObservableKeyedCollection.cs,行号:68 at TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) at [...]]]]]CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32adjustedOldIndex, Int32adjustedNewIndex) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.Colle 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.ObservableKeyedColle .RemoveItem(Int32 索引)在 [...]CollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32adjustedOldIndex, Int32adjustedNewIndex) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.Colle 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.ObservableKeyedColle .RemoveItem(Int32 索引)在 [...]ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32adjustedOldIndex, Int32adjustedNewIndex) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 在 Tether2 .OnCollectionChanged(NotifyCollectionChangedEventArgs e) 在 e:\Phil\Programozás\Modulok\TetheredSun.1.0\TetheredSun\ObservableKeyedCollection.cs,行号:68 在 TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) 在 [...]ListCollectionView.ProcessCollectionChangedWithAdjustedIndex(NotifyCollectionChangedEventArgs args, Int32adjustedOldIndex, Int32adjustedNewIndex) 在 System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 在 Tether2 .OnCollectionChanged(NotifyCollectionChangedEventArgs e) 在 e:\Phil\Programozás\Modulok\TetheredSun.1.0\TetheredSun\ObservableKeyedCollection.cs,行号:68 在 TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) 在 [...]ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 在 TetheredSun.ObservableKeyedCollection'2.OnCollectionChanged(NotifyCollectionChangedEventArgs e) 在 e:\Phil\Programozás\Modulok\TetheredSun1。 TetheredSun\ObservableKeyedCollection.cs,行号:68 在 TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) at [...]ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args) 在 System.Windows.Data.CollectionView.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 在 TetheredSun.ObservableKeyedCollection'2.OnCollectionChanged(NotifyCollectionChangedEventArgs e) 在 e:\Phil\Programozás\Modulok\TetheredSun1。 TetheredSun\ObservableKeyedCollection.cs,行号:68 在 TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) at [...]0\TetheredSun\ObservableKeyedCollection.cs,行号:68 在 TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) at [...]0\TetheredSun\ObservableKeyedCollection.cs,行号:68 在 TetheredSun.ObservableKeyedCollection`2.RemoveItem(Int32 index) at [...]

编辑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但是虽然我的调度程序不为空,但它的CheckAccess()计算结果为真,并且我在NotifyCollectionChangedEventHandler.Invoke().

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

4

1 回答 1

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);
    }
}
于 2017-07-04T21:15:26.470 回答