Когда снимать события в Silverlight - PullRequest
5 голосов
/ 17 февраля 2009

Сводка в одну строку: Какова лучшая практика для отсоединения обработчиков событий, созданных в конструкторе UserControl в Silverlight2?

Справочная информация: В настоящее время я создаю бизнес-приложение в Silverlight2. Поскольку Silverlight - это плагин для браузера, здесь нет концепции Window - все делается в UserControls. То, как я работаю с различными "формами" в приложении, заключается в том, чтобы пользовательский контроль верхнего уровня содержал Viewbox. Чтобы показать разные формы, я установил для свойства Child элемента Viewbox разные UserControls. Мое приложение имеет одноэлементный класс PageManager, который вызывается для открытия и закрытия форм. Формы (UserControls) хранятся в стеке. Открытие формы помещает ее в верхнюю часть стека, закрытие удаляет ее из стека и показывает ту, что под ней.

Я пытаюсь следовать шаблону Model-View-ViewModel. В каждой форме (производной от UserControl) у меня есть ViewModel, которая управляет всеми данными для представления. ViewModel предоставляет события, чтобы пользовательский интерфейс мог получать уведомления о завершении таких операций, как загрузка и сохранение.

В моей форме я подписываюсь на событие в конструкторе, после того как у меня есть ViewModel

public partial class MyPage : UserControl
{

    public MyViewModel ViewModel{get; set;}

    // other constructors, which create the viewmodel and call the constructor below.

    public MyPage(MyViewModel viewModel)
    {
        InitializeComponent();
        ViewModel = viewModel;
        this.LayoutRoot.DataContext = this.ViewModel;

        // subscribe to event so we can do stuff
        this.ViewModel.LoadCompleted += new MyViewModel.LoadCompletedEventHandler(ViewModel_LoadCompleted);
    }

Мой вопрос: теперь, когда я подписался на это событие, когда мне удалить обработчик? Я создаю деструктор и делаю это там, или это создает ситуацию курицы и яйца, когда сборщик мусора не разрушит объект до тех пор, пока не исчезнут все ссылки (т.е. обработчики событий)? Создать ли интерфейс, который формы должны реализовывать, который определяет функцию UnhookEvents, которая вызывается, когда форма закрывается PageManager?

Редактировать: Спасибо за ответы. Как насчет ситуации, когда ViewModel дольше, чем форма (UserControl)? Часть моего приложения позволяет пользователям создавать довольно сложную структуру, но в 95% случаев это намного проще. Я создал 2 формы, использующие одну и ту же модель представления. Пользователи могут начать заполнять простую форму, а затем переключиться в расширенный режим, который создаст новую форму, передав ей модель ViewModel.

В простой форме настройки:

    private void AdvancedSessionSetupButton_Click(object sender, RoutedEventArgs e)
    {
        PageManager.GetPageManager().Close(this);
        PageManager.GetPageManager().Open(new CreateSessionPage(this.ViewModel), "Create Session");
    }

В расширенной форме настройки:

    private void BasicSessionSetupButton_Click(object sender, RoutedEventArgs e)
    {
        PageManager.GetPageManager().Close(this);
        PageManager.GetPageManager().Open(new CreateBasicSessionPage(this.ViewModel), "Create Session");
    }

После PageManager.Close единственной вещью, ссылающейся на форму, являются события внутри ViewModel. Я думаю, что именно здесь я должен отцепить их.

Ответы [ 2 ]

2 голосов
/ 17 февраля 2009

Деструктор, более известный программистам C # как Финализаторы, в этом случае не нужен. Предполагая, что ViewModel_LoadCompleted является функцией-членом, он содержит указатель на «this», который вы даете объекту ViewModel, который полностью содержится в «this». Сборщик мусора должен разумно игнорировать это.

В этом случае правильное решение - не тратить время на их связывание.

Как правило, вам нужно отсоединить обработчик событий, когда вы передаете «this» (явно или неявно) какому-либо объекту, который будет хранить эту ссылку дольше, чем предполагаемое время жизни «this». Например, если вы установили обработчик для события родительского элемента управления. Теперь родитель имеет ссылку на вас через обработчик, а также в своей коллекции дочерних элементов управления. В этом случае вам следует отменить привязку после удаления от родителя.

Если есть сомнения, внедрите IDisposable и отмените привязку в вызове Dispose ().

1 голос
/ 17 февраля 2009

События автоматически отменяются, когда сборщик мусора проходит через ваш объект.

Но вы можете в любое время явно отменить их привязку с помощью синтаксиса "- =":

this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;

Вы можете реализовать деструктор:

~MyPage
{
    this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...