在我的程序中,我有一个从 KeyedCollection<TKey, TItem>
继承的抽象类ObservableKeyedCollection<TKey, TItem>
,并且也实现了INotifyCollectionChanged
。
实现此抽象类的实现与ListBox
绑定。在此ListBox
中,我在双击时编辑项目,并在接受后,从此ObservableKeyedCollection<TKey, TItem>
实现中删除已编辑项目的旧实例,然后添加已修改的新实例。
Windows 10创建者更新(1703,构建编号15063.250(之前,一切都很好。自更新以来,ObservableKeyedCollection<TKey, TItem>
开始使用以下消息扔InvalidOperationException
s:
呼叫线程无法访问此对象,因为一个不同的线程拥有它。
我在代码的此区域中不使用任何异步操作。
整个堆栈跟踪的时间太长,但这是从OnCollectionChanged
开始的最高部分:
在system.windows.threading.dispatcher.verifyAccess(( 在System.Windows.threading.dispatcherobject.verifyAccess(( 在system.windows.dependendencyObject.getValue(depentencyProperty dp( 在System.windows.controls.primitives.selector.getisselected(dependencyObject element(上 在System.Windows.Controls.Primitives.Selector.ItemSetisseledectectect(ItemInfo Info,boolean value( at System.windows.controls.primitives.selector.selection Changer.createdEdeltaselectionChange(list'1 unsectectionEms,list'1 selectedItems( 在system.windows.controls.primitives.selector.selection Changer.end(( 在system.windows.controls.primitives.selector.removefromselection(notifyCollectionChangeDeventargs e( 在system.windows.controls.primitives.selector.onitemschanged上 在system.windows.controls.itemscontrol.onitemcollectionChanged2(对象发送者,notifyCollectionChangeDeventargs e(上 在system.collections.specialized.notifyCollectionChangedEventHandler.Invoke(对象发送者,notifyCollectionChangeDeventargs e( 在System.Windows.Data.CollectionView.OnCollectionChanged(notifyCollectionChangeDeventargs args( 在system.windows.controls.itemcollection.onviewCollectionChanged(对象发送者,notifyCollectionChangeDeventargs e( 在system.windows.weakeventmanager.listenerlist'1.deliverevent(对象发送者,EventArgs E,type ManagerType( 在system.windows.weakeventmanager.delivereventtolist(对象发送者,EventArgs args,ListorerList列表( 在system.windows.weakeventmanager.deliverevent(对象发送者,EventArgs args( at System.Collections.specialized.CollectionChangeDeventManager.OnCollectionChanged(对象发送者,notifyCollectionChangeDeventargs args( 在System.Windows.Data.CollectionView.OnCollectionChanged(notifyCollectionChangeDeventargs args( at System.Windows.Data.listCollectionView.ProcessCollectionChangedChangedWithAdjustedIndex(notifyCollectionChangeDeventArgs args,INT32 AdjustedEddIndex,Int32 AdjustedNewIndex( 在System.Windows.Data.listCollectionView.ProcessCollectionChanged(notifyCollectionChangeDeventargs args( 在System.Windows.Data.CollectionView.OnCollectionChanged(对象发送者,notifyCollectionChangeDeventargs args( 在tetheredsun.ObservableKeyedCollection'2.OnCollectionChanged(notifyCollectionChangeDeventargs e(e: 在tetheredsun.observablekeyedCollection`2.RemoveItem(int32 index(at [...]
编辑1:
这是在Creators Update(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"));
}
问题似乎只有在我用NotifyCollectionChangedAction.Remove
操作调用OnCollectionChanged
时就会发生。用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/a/22026686/2659699,但是尽管我的调度员并非无效,但它的CheckAccess()
还是不断评估的,我一直保持相同的状态NotifyCollectionChangedEventHandler.Invoke()
。
非常感谢您的想法和帮助。
我也有类似的问题,也有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);
}
}