ListBox.ItemsSource не отключается от INotifyCollectionChanged
От: Spirit_1 Россия  
Дата: 24.04.13 15:47
Оценка:
Примерно на таком коде проявилась проблема. Есть некий объект со свойством в виде коллекции ObservableCollection
    public class CollectionHolder
    {
        public CollectionHolder()
        {
            Collection = new ObservableCollection<string> { "a", "b" };
        }

        public IList<string> Collection { get; set; }
    }


Для просмотра свойств объекта и коллекции используется окно
    public class Window2 : Window
    {
        public Window2()
        {
            lb = new ListBox();
            lb.SetBinding(ListBox.ItemsSourceProperty, "Collection");
            Content = lb;
        }

        private ListBox lb;
    }


Это окно вызывается из главного окна приложения как модальное, а потом закрывается и ссылки на него не сохраняются. DataContext обнуляется. Потом объект CollectionHolder может быть модифицирован каким либо другим потоком. Тут и возникает исключение от Dispatcher.
    public class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            holder = new CollectionHolder();
            var btn = new Button();
            Content = btn;
            btn.Click += Click;
        }

        private CollectionHolder holder;
        private int i;

        private void Click(object Sender, RoutedEventArgs E)
        {
            if (i == 0)
            {
                var win2 = new Window2 { DataContext = holder };
                win2.ShowDialog();
                win2.DataContext = null;
                GC.Collect();
                i = 1;
            }
            else
            {
                ThreadPool.QueueUserWorkItem(_ =>
                {
                    holder.Collection.Add("c"); // Exception !
                });
                i = 0;
            }
        }


Если вместо ObservableCollection применить свой класс
    public class MyList<T> : List<T>, INotifyCollectionChanged, INotifyPropertyChanged
    {
        public event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add { collectionChanged += value; }
            remove { collectionChanged -= value; }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private NotifyCollectionChangedEventHandler collectionChanged;
    }

то видно, что при байндинге в event NotifyCollectionChangedEventHandler вызывается add к методу из ListCollectionView. При установке DataContext ListBox или окна в null или другой объект или очистке байндинга у ListBox.ItemsSource remove никогда не вызывается. Как же тогда отцепить коллекцию, реализующую INotifyCollectionChanged от ListBox ?
Re: ListBox.ItemsSource не отключается от INotifyCollectionChanged
От: MxMsk Португалия  
Дата: 25.04.13 08:14
Оценка:
Здравствуйте, Spirit_1, Вы писали:

S_>то видно, что при байндинге в event NotifyCollectionChangedEventHandler вызывается add к методу из ListCollectionView. При установке DataContext ListBox или окна в null или другой объект или очистке байндинга у ListBox.ItemsSource remove никогда не вызывается. Как же тогда отцепить коллекцию, реализующую INotifyCollectionChanged от ListBox ?

Контролы WPF взаимодействуют с коллекцией не напрямую, а используя внутренний механизм CollectionView, которым манипулируют достаточно хитрожопо (пардон). Скорее всего именно из-за этого связь с коллекцией все еще остается, в то время, как в контроле ссылки уже нет.

Варианты решения:
Re[2]: ListBox.ItemsSource не отключается от INotifyCollectionChanged
От: Spirit_1 Россия  
Дата: 26.04.13 12:54
Оценка:
MM>Контролы WPF взаимодействуют с коллекцией не напрямую, а используя внутренний механизм CollectionView, которым манипулируют достаточно хитрожопо (пардон). Скорее всего именно из-за этого связь с коллекцией все еще остается, в то время, как в контроле ссылки уже нет.
Замечательно, значит после каждого соединения с ItemControl в памяти навсегда зависает CollectionView. Это ж глюк!

MM>Варианты решения:

MM> Примерно по первому варианту решил, только с точностью до наоборот. Написал потомка ListBox, который правильно подписывается и отписывается от коллекции и следит за её обновлением, а базовому ListBox отдает обычную коллекцию IEnumerable.
Re[3]: ListBox.ItemsSource не отключается от INotifyCollectionChanged
От: MxMsk Португалия  
Дата: 26.04.13 13:26
Оценка: +1
Здравствуйте, Spirit_1, Вы писали:

S_>Замечательно, значит после каждого соединения с ItemControl в памяти навсегда зависает CollectionView. Это ж глюк!

Нет, не навсегда.

S_>Примерно по первому варианту решил, только с точностью до наоборот. Написал потомка ListBox, который правильно подписывается и отписывается от коллекции и следит за её обновлением, а базовому ListBox отдает обычную коллекцию IEnumerable.

Мне кажется, наследника контрола нужно лепить только в самом крайнем случае, когда больше ничего не помогает. Завтра понадобится заменить ListBox на TreeView — мало не покажется.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.