Обработчики события привязан к объекту?

user7320
Дата: 12.05.2014 11:06:16
Туплю.

Вот объект в виде поля класса

ObservableCollection<Quest> сhildren;


вот назначаю обработчик обработчик в конструкторе этого класса

children.CollectionChanged += children_CollectionChanged;


потом где-то в коде обновляют поле этого класса

сhildren = new ObservableCollection<Quest>();


Что произёйдёт с children_CollectionChanged? Он уже не будет работать? Ведь старый объект сhildren уже скормлен сборщику мусора.
Antonariy
Дата: 12.05.2014 11:12:21
Конечно не будет.
user7320
Дата: 12.05.2014 12:52:41
Antonariy
Конечно не будет.

Значит, если я хочу, чтобы к новому объекту children всегда был привязан этот обработчик, мне надо везде, где происходит присвоение нового children, добавлять подписку на этот обработчик. Так? Скажем, в сеттере, да?

Ну и тогда завести правило, что даже если внутри самого класса присваивается новый children, то это должно делаться через свойство. А то я иногда внутри класса работаю прямо с полями, а вот в таком сценарии это недопустимо.

Так?

Извините, что туплю - я в последнее время что-то не уверен даже в элементарных вещах. Их элеметарность подкупает.
Алексей К
Дата: 12.05.2014 12:59:38
user7320
Ну и тогда завести правило, что даже если внутри самого класса присваивается новый children, то это должно делаться через свойство. А то я иногда внутри класса работаю прямо с полями, а вот в таком сценарии это недопустимо.

Так?
Так. И отписаться от старого значения не помешает.
public ObservableCollection<Item> Children
{
    get { return _children; }
    set
    {
        if (_children != null)
            _children.CollectionChanged -= children_CollectionChanged;

        _children = value;

        if (_children != null)
            _children.CollectionChanged += children_CollectionChanged;
    }
}

ObservableCollection<Item> _children;
Antonariy
Дата: 12.05.2014 13:01:12
Не совсем понял суть проблемы. Если она в том, чтобы привязка обработчиков не терялась вместе с объектом (типа обработчиков произвольно много и заранее неизвестно сколько), то можно завести переменную, в которой все это хранить:

varCollectionChanged += children_CollectionChanged;

//после убийства старого и создания нового объекта

children.CollectionChanged = varCollectionChanged;
user7320
Дата: 12.05.2014 13:09:21
Antonariy
Не совсем понял суть проблемы. Если она в том, чтобы привязка обработчиков не терялась вместе с объектом (типа обработчиков произвольно много и заранее неизвестно сколько), то можно завести переменную, в которой все это хранить:

varCollectionChanged += children_CollectionChanged;

//после убийства старого и создания нового объекта

children.CollectionChanged = varCollectionChanged;

Хмм, тоже вариант. А делегат (это же делегат?) много места в памяти занимает? Ну, т. е. такие операции не накладны?

Алексей К
user7320
Ну и тогда завести правило, что даже если внутри самого класса присваивается новый children, то это должно делаться через свойство. А то я иногда внутри класса работаю прямо с полями, а вот в таком сценарии это недопустимо.

Так?
Так. И отписаться от старого значения не помешает.
public ObservableCollection<Item> Children
{
    get { return _children; }
    set
    {
        if (_children != null)
            _children.CollectionChanged -= children_CollectionChanged;

        _children = value;

        if (_children != null)
            _children.CollectionChanged += children_CollectionChanged;
    }
}

ObservableCollection<Item> _children;

Да, и ещё проверка value на равенство текущему значению, чтобы обработчики лишний раз не гонять туда-сюда.
Antonariy
Дата: 12.05.2014 13:15:05
user7320
А делегат (это же делегат?) много места в памяти занимает?
Копьище, это же ссылки на адреса в памяти, по которым разместились обработчики. А делегат ли это, я х.з.
Pallaris
Дата: 12.05.2014 13:23:28
user7320
Значит, если я хочу, чтобы к новому объекту children всегда был привязан этот обработчик, мне надо везде, где происходит присвоение нового children, добавлять подписку на этот обработчик. Так? Скажем, в сеттере, да?


Вместо этого
сhildren = new ObservableCollection<Quest>();


сделай
сhildren.Clear();


и не будет тебе геморроя
user7320
Дата: 12.05.2014 13:46:24
Pallaris
user7320
Значит, если я хочу, чтобы к новому объекту children всегда был привязан этот обработчик, мне надо везде, где происходит присвоение нового children, добавлять подписку на этот обработчик. Так? Скажем, в сеттере, да?


Вместо этого
сhildren = new ObservableCollection<Quest>();


сделай
сhildren.Clear();


и не будет тебе геморроя

Да, это тоже вариант. Просто у меня разные сценарии могут быть - может быть не

сhildren = new ObservableCollection<Quest>();


а прилетать конкретная заполненная коллеция. Тогда придётся её элементы копировать.

Вобщем, главное, я узнал про обработчики. И получил некоторые варианты работы в разных сценариях. Всем спасибо.
user7320
Дата: 12.05.2014 16:28:22
Продолжим тему.

Значит, решил я воспользоваться советом Антонария и вынести делегат в отдельное поле. Это мне нужно было в т. ч. и для того, чтобы воспользоваться сериализацией.

Делаю так.

Класс Quest помечен атрибутом Serializable и в нём есть поля

protected ObservableCollection<Quest> _children;
protected NotifyCollectionChangedEventHandler _children_CollectionChanged;


В конструторе класса делаю так

_children_CollectionChanged = Children_CollectionChanged;

_children = new ObservableCollection<Quest>();
_children.CollectionChanged += _children_CollectionChanged;


Затем сериализую и десериализую

Quest quest = quest.DeepClone();


Всё, что делает DeepClone(), это

        public static T DeepClone<T>(this T obj)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(ms, obj);
                ms.Position = 0;
                return (T)bf.Deserialize(ms);
            }
        }


Затем добавляю в коллецию потомков объекта quest один объект

model.Children.Add(new Quest());


И метод Children_CollectionChanged НЕ ВЫЗЫВАЕТСЯ. Почему? Я же его сериализовал.