Отмена подписки на событие CollectionChanged коллекции, хранящейся в присоединенном свойстве

Итак, у меня есть присоединенное свойство (объявленное в статическом классе), которое присоединяет свойство INotifyCollectionChanged к объекту.

Когда свойство установлено, я хочу начать мониторинг коллекции на предмет изменений, а затем выполнить какое-то действие над объектом, к которому эта коллекция прикреплена.

Первая попытка:

private static void MyProperty_OnChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
    // We need both the dependency object, and the collection args to process the notification
    NotifyCollectionChangedEventHandler changedFunc = (sender, eventArgs) => MyProperty_OnCollectionChanged( d, sender, eventArgs );

    if( e.OldValue != null )
        e.OldValue.CollectionChanged -= changedFunc;   // Can you see the bug?
    if( e.NewValue != null )
        e.NewValue.CollectionChanged += changedFunc;

}

Чтобы поместить объект, к которому прикреплена коллекция, в обработчик, я втягиваю d в замыкание. Достаточно просто, правда?

Что ж, я уверен, что вы можете увидеть здесь ошибку. Когда коллекция удаляется или заменяется новой, ей не удается отменить регистрацию обработчика событий, потому что changedFunc - это новый обработчик с другим закрытием.

Итак, как правильно это сделать?


person Mark    schedule 02.12.2011    source источник


Ответы (2)


Из вашего кода не ясно, где живет этот статический метод.

Есть ли способ сохранить обработчик событий как переменную-член того класса, к которому он принадлежит? Это будет единичная ссылка, которую можно добавлять и удалять по мере необходимости. В настоящее время вы создаете новый обработчик событий каждый раз, когда срабатывает MyProperty_OnChanged.

В качестве альтернативы, можете ли вы изменить свою коллекцию, чтобы сохранить ссылку на обработчик событий, чтобы вы могли получить к нему доступ через e.OldValue.OldHandler (или аналогичный), чтобы у вас был доступ к нему позже?

person Joe    schedule 02.12.2011
comment
Поскольку это присоединенное свойство, нет класса, членом которого я мог бы сохранить обработчик. В настоящее время я храню другой объект в другом присоединенном свойстве, чтобы решить эту проблему, но я ищу более чистое решение. - person Mark; 05.12.2011
comment
Кроме того, это не моя коллекция. Присоединенное свойство должно работать с любым INotifyCollectionChanged реализующим объектом. - person Mark; 05.12.2011

Я решил эту проблему, используя другое присоединенное свойство для хранения частного объекта, содержащего обработчик событий и ссылку на d. Фактически я явно создаю закрывающий класс и сохраняю на него ссылку.

Но мне это кажется довольно жестким подходом, я действительно искал более элегантное решение.

person Mark    schedule 09.12.2011