How to destroy or detach a CollectionView

流过昼夜 提交于 2019-12-23 20:03:23

问题


I observe an odd behaviour of WPF ItemsControls: If a set the ItemsSource to an object which implements INotifyCollectionChanged and after that set the ItemsSource to null, the CollectionView which was created to provide the data to the ItemsControl still listens to the CollectionChanged-event of the source object.
If now the source collection is changed through a different thread, the CollectionView throws an exception (without being attached to any control). While I understand why this is happening, I’m really stuck resolving this situation.

Therefore the main question is, how can I destroy a CollectionView so that it does not listen any more to CollectionChanged-event. Or how can I disable it doing that / detaching the underlying collection.

Please note: The described behavior is not with ObservableCollection. The source object is an IEnumerable of T and implements INotifyCollectionChanged.


回答1:


You're looking for the CollectionView.DetachFromSourceCollection() method:

var collectionView = CollectionViewSource.GetDefaultView(yourEnumerable) as CollectionView;
collectionView.DetachFromSourceCollection();



回答2:


Update It seems, that under .net 4.5 there is this desired functionality. See the answer of HighCore. For those not having 4.5 I leave my workaround here, maybe it helps someone:

class DetachableNotifyCollectionChangedWrapper : IEnumerable, INotifyCollectionChanged {
        IEnumerable m_source;
        public event NotifyCollectionChangedEventHandler CollectionChanged;
        public DetachableNotifyCollectionChangedWrapper(IEnumerable enumerable) {
            if (null == enumerable) throw new ArgumentNullException("enumerable"); ;
            m_source = enumerable;
            var ncc = m_source as INotifyCollectionChanged;
            if (null != ncc) ncc.CollectionChanged += SourceCollectionChanged;
        }
        void SourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
            if (null != CollectionChanged) CollectionChanged(this,e);
        }
        public IEnumerator GetEnumerator() {
            return m_source.GetEnumerator();
        }
        public void Detach() {
            var ncc = m_source as INotifyCollectionChanged;
            if (null != ncc) ncc.CollectionChanged -= SourceCollectionChanged;
        }            
}

To use this, set the Wrapper as the ItemsSource of the ItemsControl. Before setting then the ItemsSource to null, call Detach on the wrapper to unregister the changed-event. Something as follows:

var wrapper = m_lstLog.ItemsSource as DetachableNotifyCollectionChangedWrapper;
if (null != wrapper) wrapper.Detach();
m_lstLog.ItemsSource = null;    

The wrapper can also be used from within a ViewModel.



来源:https://stackoverflow.com/questions/28439865/how-to-destroy-or-detach-a-collectionview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!