我观察到WPF ItemsControls的奇怪行为:如果将ItemsSource设置为实现INotifyCollectionChanged
的对象,然后将ItemsSource
设置为null,则创建为CollectionView
向ItemsControl提供数据仍然监听源对象的CollectionChanged
- 事件
如果现在通过不同的线程更改了源集合,则CollectionView
会抛出异常(不附加到任何控件)。
虽然我理解为什么会这样,但我真的无法解决这种情况。
因此,主要问题是,如何销毁CollectionView
以便它不再听CollectionChanged
- 事件。或者我如何禁用它/分离底层集合。
请注意:所描述的行为不适用于ObservableCollection
。源对象是T的IEnumerable
并实现INotifyCollectionChanged
。
答案 0 :(得分:3)
您正在寻找CollectionView.DetachFromSourceCollection()
方法:
var collectionView = CollectionViewSource.GetDefaultView(yourEnumerable) as CollectionView;
collectionView.DetachFromSourceCollection();
答案 1 :(得分:2)
<强>更新强> 看来,在.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设置为ItemsControl的ItemsSource
。在设置然后将ItemsSource
设置为null之前,请在包装器上调用Detach以取消注册已更改的事件。如下:
var wrapper = m_lstLog.ItemsSource as DetachableNotifyCollectionChangedWrapper;
if (null != wrapper) wrapper.Detach();
m_lstLog.ItemsSource = null;
也可以在ViewModel中使用包装器。