开发者

Unsubscribe EventAggregator events in ViewModels

开发者 https://www.devze.com 2023-03-01 03:44 出处:网络
I start using WPF with PRISM and MVVM. One problem I am facing is that I can’t find a good place / best practice to unsubscribe EventAggregator events formerly subscribed in the ViewModel. The follow

I start using WPF with PRISM and MVVM. One problem I am facing is that I can’t find a good place / best practice to unsubscribe EventAggregator events formerly subscribed in the ViewModel. The following solution - calling Unsubscribe in the destructor – is much too late. It is just running with the next garbage collection.

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

    ~ViewModel()
    {
        var eventAggregator = ServiceLocator.Cu开发者_JAVA百科rrent.GetInstance<IEventAggregator>();
        eventAggregator.GetEvent<SeriesSelectionChangedEvent>().Unsubscribe(OnSeriesSelectionChanged);
    }

    void OnSeriesSelectionChanged(SeriesSelectionChangedEventArgs e)
    {
    }
}


It's up to you! If your application can notify ViewModel when it is no longer needed, so you should unsubscribe there.

For example, in our project we have IViewDisposeService. If view (or its model) needs deterministic finalization, it registers itself in IViewDisposeService when showing. Then the Core use the same service to notify registered views when they've been removed from regions.

Another way is to use commands. Your model expose command which must be invoked by a view when it is closing. ViewModel may use command handler to unsubscribe.

By the way, if you worry that EventAggregator will hold your ViewModel, it's not a problem, because Prism's EventAggregator use weak references.


Well sometime back, I also faced the same issue. Here's what we did (WPF App).

  1. Create a new base class - DisposableUserControl : UserControl, IDisposable. This will contain the logic of disposing an user control. Code added in the end.
  2. Replace all user control in your application with DisposableUserControl. like < app: DisposableUserControl .... > < / app.DisposableUserControl>
  3. Add an OnDispose method (Virtual) in ViewModelBase which is called in Dispose () method of VM.Each ViewModel of your app should override this OnDispose method in which you'll unsubscribe your events. Something like-
    OnDispose() { base.Dispose(); UnsubscribeEvent (abcEventSubscribername); }

Code

    /// <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;
                }
            }
        }
    }


You could have the View notify the ViewModel when it is unloaded (or in case of a Window when it is closed). Then in the Unloaded/Closed handler in the ViewModel you could unsubscribe. That is the way I do it in my application.

0

精彩评论

暂无评论...
验证码 换一张
取 消