MVVM Light: как отменить регистрацию Messenger

Мне нравится MVVM Light's Messenger и его гибкость, однако у меня возникают утечки памяти, когда я забываю явно отменить регистрацию получателей (в Silverlight 4).

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

  • ViewModels просты: вы обычно полностью контролируете их жизненный цикл и можете просто Cleanup () их, когда они больше не нужны.

  • Представления , с другой стороны, сложнее, поскольку они создаются и уничтожаются с помощью DataTemplates. Например, вы можете представить себе ItemsControl с MyView как DataTemplate, привязанный к ObservableCollection . Элементы управления MyView создаются / собираются механизмом привязки, и у вас нет хорошего способа вручную вызвать для них Cleanup ().

У меня есть решение, но я хотел бы знать, подходит ли оно узор или есть лучшие альтернативы. Идея состоит в том, чтобы отправить конкретное сообщение из ViewModel, чтобы сообщить связанным View (-ам), что нужно удалить:

public class MyViewModel : ViewModelBase
{
    ...

    public override void Cleanup()
    {
        // unregisters its own messages, so that we risk no leak
        Messenger.Default.Unregister<...>(this);

        // sends a message telling that this ViewModel is being cleaned
        Messenger.Default.Send(new ViewModelDisposingMessage(this));

        base.Cleanup();
    }
}

public class MyView : UserControl, ICleanup
{
    public MyView()
    {
         // registers to messages it actually needs
         Messenger.Default.Register<...>(this, DoSomething);

         // registers to the ViewModelDisposing message
         Messenger.Default.Register(this, m =>
             {
                 if (m.SenderViewModel == this.DataContext)
                     this.Cleanup();
             });
    }

    public void Cleanup()
    {
        Messenger.Default.Unregister<...>(this);
        Messenger.Default.Unregister(this);
    }
}

Итак, когда вы вызываете Cleanup () на viewModel, все представления, которые используют его как DataContext, будут выполнять свою локальную Cleanup () тоже.

Что ты думаешь? Я упустил что-то очевидное?

42
задан Francesco De Vittori 14 March 2011 в 21:57
поделиться