C#学习教程:ObservableCollection:使用多个新项调用OnCollectionChanged后者确实有效,但对于大型集合来说效率不高。所以我继承了ObservableCollection:publicclassSuspendableObservableCollection:ObservableCollection出于某种原因,这段代码:...publicvoidFlushCache(){if(_cachedItems.Count>0){foreach(varitemin_cachedItems)Items.Add(item);OnCollectionChanged(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,(IList)_cachedItems));引发引用不属于集合的项目的集合添加事件这似乎是BCL中的错误?我可以一步一步看到新项目添加到this.ItemsbeforeOnCollectionChangediscalledWow刚刚有了一个惊人的发现。这些方法都不适合我(flush、addrange),因为只有当这个集合绑定到我的Listview时才会触发错误!TestObservableCollectiontestCollection=newTestObservableCollection();列出testTrades=newList();对于(inti=0;i<200000;i++)testTrades.Add(t);testCollection.AddRange(测试交易);//这里没有问题.._trades.AddRange(testTrades);//这个绑定到ListView..BOOOM!!!简而言之,ObservableCollection确实支持添加增量列表,但ListView不支持。Andyp想出了一个解决方法,使其适用于下面的CollectionView,但由于调用了.Refresh(),它与调用OnCollectionChanged(.Reset)没有什么不同。您可以作为ObservableCollection实现AddRange(),如下所示:publicclassRangeObservableCollection:ObservableCollection{privatebool_SuppressNotification;公共覆盖事件NotifyCollectionChangedEventHandlerCollectionChanged;protectedvirtualvoidOnCollectionChangedMultiItem(NotifyCollectionChangedEventArgse){NotifyCollectionChangedEventHandlerhandlers=this.CollectionChanged;if(handlers!=null){foreach(NotifyCollectionChangedEventHandlerhandlers.GetInvocationList()){if(handler.TargetisCollectionView)((CollectionView)handler.Target).Refresh();否则处理程序(这,e);}}}protectedoverridevoidOnCollectionChanged(NotifyCollectionChangedEventArgse){if(!_SuppressNotification){base.OnCollectionChanged(e);如果(CollectionChanged!=null)CollectionChanged.Invoke(this,e);}}publicvoidAddRange(IEnumerablelist){if(list==null)thrownewArgumentNullException("list");_SuppressNotification=真;前额ch(列表中的T项){添加(项);}_SuppressNotification=false;OnCollectionChangedMultiItem(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,list));更新:根据这篇文章,我在绑定到ListBox后也看到了InvalidOperationException(你会看到相同的消息),因为CollectionView不支持范围操作。幸运的是,这篇文章也提供了一个解决方案(虽然感觉有点“hack-ish”)。更新2:添加了一个修复程序以在覆盖的OnCollectionChanged()实现中引发覆盖的CollectionChanged事件。感谢AndyP的灵感。我的实现存在一些问题,例如在测试中使用CollectionView而不是ICollectionView,以及在元素上手动调用“Reset”。从CollectionView继承的元素实际上可能以比调用“this.Reset()”更多的方式处理这些参数,因此最好仍然触发它们的处理程序并只使用它们需要的Action=Reset参数而不是改进的事件参数包括列表已更改的项目。下面是我的(非常相似的)实现。publicclassBaseObservableCollection:ObservableCollection{//Flag用于防止OnCollectionChanged在Add(IEnumerable)和Clear()等批量操作期间触发privatebool_SuppressCollectionChanged=false;///重写以便我们可以手动调用已注册的处理程序并区分那些需要和不需要Action.Resetargs的处理程序。公共覆盖事件NotifyCollectionChangedEventHandlerCollectionChanged;publicBaseObservableCollection():base(){}publicBaseObservableCollection(IEnumerabledata):base(data){}#region事件处理程序受保护的覆盖如果(CollectionChanged!=null)CollectionChanged.Invoke(this,e);}}//CollectionViews在传递一个NotifyCollectionChangedEventArgs时引发错误,该NotifyCollectionChangedEventArgs指示不止一个元素已被添加或移除。他们喜欢er接收“Action=Reset”通知,但这不适合//代码中的应用程序,因此我们实际上检查我们正在通知的类型并传递自定义事件参数。protectedvirtualvoidOnCollectionChangedMultiItem(NotifyCollectionChangedEventArgse){NotifyCollectionChangedEventHandlerhandlers=this.CollectionChanged;if(handlers!=null)foreach(NotifyCollectionChangedEventHandlerhandlers.GetInvocationList())handler(this,!(handler.TargetisICollectionView)?e:newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));}#endregion#region扩展集合方法protectedoverridevoidClearItems(){if(this.Count==0)return;删除列表=新列表(this);_SuppressCollectionChanged=真;base.ClearItems();_SuppressCollectionChanged=假;OnCollectionChangedMultiItem(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,removed));}publicvoidAdd(IEnumerabletoAdd){if(this==toAdd)thrownewException("无效操作。这将导致在修改集合时对其进行迭代。");_SuppressCollectionChanged=真;foreach(TitemintoAdd)Add(item);_SuppressCollectionChanged=假;OnCollectionChangedMultiItem(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,newList(toAdd)));}publicvoidRemove(IEnumerabletoRemove){if(this==toRemove)thrownewException("这会导致迭代正在修改的集合。");_SuppressCollectionChanged=真;foreach(TitemintoRemove)Remove(item);_SuppressCollectionChanged=假;OnCollectionChangedMultiItem(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove)to;}#endregion}经过多次迭代,我们最终得到了这个版本的ObservableRangeCollection和ReadOnlyObservableRangeCollection,基于接受的答案的代码,我们在过去6个月内没有修改过:公共类ObservableRangeCollection:ObservableCollection{privateboolsuppressNotification;publicObservableRangeCollection(){}publicObservableRangeCollection(IEnumerableitems):base(items){}publicoverrideeventNotifyCollectionChangedEventHandlerCollectionChanged;protectedvirtualvoidOnCollectionChangedMultiItem(NotifyCollectionChangedEventArgse){varhandlers=CollectionChanged;如果(处理程序==null)返回;foreach(NotifyCollectionChangedEventHandlerhandlersinhandlers.GetInvocationList()){if(handler.TargetisReadOnlyObservableCollection&&!(handler.TargetisReadOnlyObservableRangeCollection)){thrownewNotSupportedException("ObservableRangeCollection包装在ReadOnlyObservableCollection中,它可能绑定到ItemsControl"+"在内部使用不支持范围操作的ListCollectionView。n"+"而不是ReadOnlyObservableCollection,使用ReadOnlyObservableRangeCollection");}varcollectionView=handler.Target作为ICollectionView;if(collectionView!=null){collectionView.Refresh();}else{handler(this,e);}}}protectedoverridevoidOnCollectionChanged(NotifyCollectionChangedEventArgse){if(suppressNotification)返回;base.OnCollectionChanged(e);如果(CollectionChanged!=null){CollectionChanged.Invoke(this,e);}}publicvoidAddRange(IEnumerableitems){if(items==null)return;抑制通知=真;varitemList=items.ToList();foreach(itemList中的varitem){添加(项目);}suppressNotification=false;如果(itemList.Any()){OnCollectionChangedMultiItem(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,itemList));}}publicvoidAddRange(paramsT[]items){AddRange((IEnumerable)items);}publicvoidReplaceWithRange(IEnumerableitems){Items.Clear();OnCollectionChanged(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));添加范围(项目);}publicvoidRemoveRange(IEnumerableitems){suppressNotification=true;varremovableItems=items.Where(x=>Items.Contains(x)).ToList();foreach(variteminremovableItems){Remove(item);}suppressNotification=false;如果(removableItems.Any()){OnCollectionChangedMultiItem(newNotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,removableItems));}}}publicclassReadOnlyObservableRangeCollection:ReadOnlyObservableCollection{publicReadOnlyObservableRangeCollection(ObservableCollectionlist):base(list){}受保护的覆盖事件protectedoverridevoidOnCollectionChanged(NotifyCollectionChangedEventArgse){varhandlers=CollectionChanged;如果(处理程序==null)返回;foreach(处理程序中的NotifyCollectionChangedEventHandler处理程序。GetInvocationList()){varcollectionView=handler.TargetasICollectionView;if(collectionView!=null){collectionView.Refresh();}别的{处理程序(这个,e);我们基本上用ObservableCollection替换了我们应用程序中所有ObservableCollection的使用,它就像一个魅力我相信你需要将它转换为IList:以上是C#学习教程:ObservableCollection:使用多个新项调用OnCollectionChanged共享所有内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多加关注——本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
