代码之家  ›  专栏  ›  技术社区  ›  HCL

如何销毁或分离CollectionView

  •  3
  • HCL  · 技术社区  · 10 年前

    我观察到WPF ItemsControls的一个奇怪行为:如果将ItemsSource设置为实现 INotifyCollectionChanged 然后设置 ItemsSource 为null CollectionView 为向ItemsControl提供数据而创建的控件仍然侦听 CollectionChanged -源对象的事件。
    如果现在通过不同的线程更改了源集合 集合视图 抛出异常(不附加到任何控件)。 虽然我明白为什么会发生这种情况,但我真的很难解决这种情况。

    因此,主要问题是,我如何才能摧毁 集合视图 这样它就不再听了 集合已更改 -事件。或者,我如何禁用它,这样做/分离基础集合。

    请注意:所描述的行为与 ObservableCollection 。源对象是 IEnumerable T和机具 INotifyCollectionChanged(通知集合已更改) .

    2 回复  |  直到 10 年前
        1
  •  3
  •   Fede    10 年前

    您正在寻找 CollectionView.DetachFromSourceCollection() 方法:

    var collectionView = CollectionViewSource.GetDefaultView(yourEnumerable) as CollectionView;
    collectionView.DetachFromSourceCollection();
    
        2
  •  2
  •   HCL    10 年前

    使现代化 看起来,在.net 4.5下有这样的功能。查看HighCore的答案。对于那些没有4.5的人,我把我的解决方法留在这里,也许这会帮助一些人:

    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;
            }            
    }
    

    要使用此功能,请将Wrapper设置为 ItemsSource ItemsControl的。在设置之前 项目来源 如果为null,则在包装器上调用Detach以注销更改的事件。以下内容:

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

    包装器也可以在ViewModel中使用。

    推荐文章