Автоматический вызов OnDetaching () для поведения Silverlight - PullRequest
5 голосов
/ 22 апреля 2010

Я использую несколько режимов наложения и триггеры на элементе управления Silverlight. Мне интересно, существует ли какой-либо механизм для автоматического отсоединения или обеспечения вызова OnDetaching () для поведения или триггера, когда элемент управления больше не используется (т.е. удален из визуального дерева).

Моя проблема в том, что произошла управляемая утечка памяти с элементом управления из-за одного из вариантов поведения. Поведение подписывается на событие некоторого долгоживущего объекта в переопределении OnAttached () и должно отписываться от этого события в переопределении OnDetaching (), чтобы оно могло стать кандидатом на сборку мусора. Однако OnDetaching (), кажется, никогда не вызывается, когда я удаляю элемент управления из визуального дерева ... единственный способ, которым я могу это сделать, - это явное отключение проблемного поведения ПЕРЕД удалением элемента управления, а затем он должным образом собирает мусор .

Прямо сейчас мое единственное решение состояло в том, чтобы создать общедоступный метод в выделенном фрагменте кода для элемента управления, который может проходить и отключать любые известные способы поведения, которые могут вызвать проблемы со сборкой мусора. Клиентский код должен знать, как это вызвать, прежде чем удалять элемент управления с панели. Мне не очень нравится этот подход, поэтому я ищу какой-то автоматический способ сделать это, который я пропускаю, или лучшее предложение.

public void DetachBehaviors()
{
     foreach (var behavior in Interaction.GetBehaviors(this.LayoutRoot))
     {
          behavior.Detach();
     }

     //continue detaching all known problematic behaviors on the control....
}

Ответы [ 2 ]

3 голосов
/ 28 февраля 2012

Joost van Schaik предлагает альтернативный способ очистки ссылок от прикрепленного поведения, избегая при этом проблемы с утечкой памяти. Это зависит от выполнения работы по очистке с использованием делегатов событий Loaded и Unloaded объекта AssociatedObject.

Он также предлагает фрагмент кода для создания заглушек для прикрепленного поведения.

3 голосов
/ 23 апреля 2010

В этом случае вам действительно необходим не какой-то способ автоматического отсоединения, а обеспечение того, чтобы ссылка, хранящаяся в долгоживущем объекте, не удерживала поведение (и, следовательно, все остальное, на которое он ссылается) от сбора мусора.

Это достигается путем реализации шаблона посредника. Концепция заключается в том, что вы не предоставляете долгоживущему объекту делегат со ссылкой на ваш Behaviour, вместо этого вы создаете класс Mediator в качестве посредника. Посредник присоединяется к событию долгоживущих объектов и сохраняет WeakReference для поведения. Когда долгоживущий объект запускает событие, посредник проверяет, что WeakReference еще жив, если это так, вызывает метод для передачи события. Если при возникновении события посредник обнаруживает, что WeakReference больше не существует, он отсоединяет свой обработчик события от долгоживущего объекта.

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

К счастью, вам не нужно создавать это самостоятельно, другие уже сделали это. Это называется WeakEventListener. Этот блог: Выделение «слабого» вклада; Улучшения делают предотвращение утечек памяти с помощью WeakEventListener еще проще! имеет отличный набор ссылок по теме.

...