Как уничтожить или отсоединить CollectionView

Я наблюдаю странное поведение WPF ItemsControls: если установить ItemsSource на объект, который реализует INotifyCollectionChanged, а после этого установить ItemsSource в значение null, CollectionView, который был создан для передачи данных в ItemsControl, по-прежнему будет прослушивать CollectionChanged-событие исходный объект.
Если теперь исходная коллекция изменяется через другой поток, CollectionView генерирует исключение (без привязки к какому-либо элементу управления). Хотя я понимаю, почему это происходит, я действительно застрял в разрешении этой ситуации.

Поэтому главный вопрос: как мне уничтожить CollectionView, чтобы он больше не слушал CollectionChanged-событие. Или как я могу отключить это / отсоединить базовую коллекцию.

Обратите внимание: описанное поведение не применимо к ObservableCollection. Исходный объект - это IEnumerable из T и реализует INotifyCollectionChanged.


person HCL    schedule 10.02.2015    source источник
comment
Вызов clear () недостаточно в вашем случае, тогда вы можете установить пустой шаблон, когда Count == 0.   -  person XAMlMAX    schedule 10.02.2015
comment
Ясно на чем? Исходный объект?   -  person HCL    schedule 10.02.2015
comment
вместо того, чтобы устанавливать для коллекции значение null. Извините, мне следовало прояснить этот момент. ИЗМЕНИТЬ, но я помню, что существует проблема с представлением, собирающим изменения, когда вы вызываете метод clear в ObservableCollection, я найду этот пост и вернусь к вам с дополнительной информацией.   -  person XAMlMAX    schedule 11.02.2015
comment
Ах, нашел сообщение, и это в основном подразумевает, что если ваши объекты в вашем списке сложные и к ним прикреплены какие-то обработчики, будет сложно отсоединить обработчики. Вот сообщение.   -  person XAMlMAX    schedule 11.02.2015
comment
@XAMIMAX: это не ObservableCollection, но я нашел решение, см. Ниже. Спасибо, в любом случае!   -  person HCL    schedule 11.02.2015


Ответы (2)


Вы ищете CollectionView.DetachFromSourceCollection() метод:

var collectionView = CollectionViewSource.GetDefaultView(yourEnumerable) as CollectionView;
collectionView.DetachFromSourceCollection();
person Federico Berasategui    schedule 10.02.2015
comment
Да, точно! Но, к сожалению, этот метод доступен только в .net 4.5, а приложение, над которым я сейчас работаю, - 4.0. - person HCL; 10.02.2015

Обновление Похоже, что в .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. Перед установкой ItemsSource в значение null вызовите Detach в оболочке, чтобы отменить регистрацию измененного события. Что-то вроде следующего:

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

Обертку также можно использовать из ViewModel.

person HCL    schedule 10.02.2015