Отписаться от событий EventAggregator во ViewModels - PullRequest
6 голосов
/ 28 апреля 2011

Я начинаю использовать WPF с PRISM и MVVM.Одна проблема, с которой я сталкиваюсь, заключается в том, что я не могу найти подходящее место / лучшие практики для отмены подписки на события EventAggregator, ранее подписанные в ViewModel.Следующее решение - вызвать Unsubscribe в деструкторе - слишком поздно.Он просто запускается со следующей сборкой мусора.

public class ViewModel : ViewModelBase
{
    public ViewModel()
    {
        var eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
        eventAggregator.GetEvent<SeriesSelectionChangedEvent>().Subscribe(OnSeriesSelectionChanged);
    }

    ~ViewModel()
    {
        var eventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
        eventAggregator.GetEvent<SeriesSelectionChangedEvent>().Unsubscribe(OnSeriesSelectionChanged);
    }

    void OnSeriesSelectionChanged(SeriesSelectionChangedEventArgs e)
    {
    }
}

Ответы [ 3 ]

4 голосов
/ 28 апреля 2011

Это зависит от вас! Если ваше приложение может уведомить ViewModel о том, что оно больше не нужно, вам следует отписаться там.

Например, в нашем проекте у нас есть IViewDisposeService. Если представление (или его модель) нуждается в детерминированной финализации, при регистрации оно регистрируется в IViewDisposeService. Затем ядро ​​использует тот же сервис, чтобы уведомлять зарегистрированные представления об удалении их из регионов.

Другой способ - использовать команды. Ваша модель выставляет команду, которая должна вызываться представлением, когда оно закрывается. ViewModel может использовать обработчик команд для отмены подписки.

Кстати, если вы беспокоитесь, что EventAggregator будет удерживать вашу ViewModel, это не проблема, потому что EventAggregator Prism использует слабые ссылки.

3 голосов
/ 29 апреля 2011

Ну, когда-то, я тоже столкнулся с той же проблемой.Вот что мы сделали (WPF App).

  1. Создайте новый базовый класс - DisposableUserControl : UserControl, IDisposable.Это будет содержать логику удаления пользовательского элемента управления.Код добавлен в конце.
  2. Замените все пользовательские элементы управления в вашем приложении DisposableUserControl.например </ app.DisposableUserControl>
  3. Добавить метод OnDispose (Virtual) в ViewModelBase, который вызывается в методе Dispose () VM.Each.Метод OnDispose, с помощью которого вы отмените подписку на ваши события.Что-то вроде -
    OnDispose () {base.Dispose ();UnsubscribeEvent (abcEventSubscribername);}

Код

    /// <summary>
    /// Falg used to avoid calling dispose multiple times on same user control
    /// </summary>
    private bool isDisposed;



   /// <summary>
    /// Dispose
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);           
    }

    /// <summary>
    /// If disposing equals true, the method has been called directly
    /// or indirectly by a user's code. Managed and unmanaged resources
    /// can be disposed. If disposing equals false, the method has been called by the 
    /// runtime from inside the finalizer and you should not reference 
    /// other objects, only unmanaged resources can be disposed.
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!this.isDisposed)
        {
            this.isDisposed = true;
            if (disposing)
            {
                UtilityFunctions.DisposeChildDisposableUserControls(this);

                if (this.DataContext != null && this.DataContext is IDisposable)
                {
                    var parent = LogicalTreeHelper.GetParent(this);

                    if (parent == null || ((parent as FrameworkElement).DataContext != this.DataContext))
                    {
                        (this.DataContext as IDisposable).Dispose();
                    }
                    BindingOperations.ClearAllBindings(this);
                    this.DataContext = null;
                }
            }
        }
    }
2 голосов
/ 29 апреля 2011

Вы можете сделать так, чтобы View уведомлял ViewModel, когда он выгружен (или в случае Window, когда он закрыт). Затем в обработчике Unloaded / Closed в ViewModel вы можете отписаться. Так я делаю это в своем приложении.

...