Unsubscribe EventAggregator Events in ViewModels

I am starting to use WPF with PRISM and MVVM. One of the problems I am facing is that I cannot find a good place / best practice to undo the EventAggregator events previously signed into the ViewModel. The next solution - calling Unsubscribe in the destructor - is too late. It just works 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.Current.GetInstance<IEventAggregator>(); eventAggregator.GetEvent<SeriesSelectionChangedEvent>().Unsubscribe(OnSeriesSelectionChanged); } void OnSeriesSelectionChanged(SeriesSelectionChangedEventArgs e) { } } 
+6
source share
3 answers

It is for you! If your application can notify ViewModel when it is no longer required, you must unsubscribe.

For example, in our project we have IViewDisposeService. If a view (or its model) needs deterministic finalization, it is registered in the IViewDisposeService when displayed. Core then uses the same service to notify recorded views when they have been removed from the regions.

Another way is to use commands. Your model sets the command that should be called by the view when it is closed. ViewModel can use a command handler to unsubscribe.

By the way, if you are worried that the EventAggregator will save your ViewModel, this is not a problem because the Prism EventAggregator uses weak links.

+3
source

Well, sometime ago, I also ran into the same problem. Here's what we did (WPF app).

  • Create a new base class - DisposableUserControl : UserControl, IDisposable. This will contain the disposition logic of the user control. The code is added at the end.
  • Replace all user controls in the application with the DisposableUserControl utility. like <app: DisposableUserControl ....> </app.DisposableUserControl>
  • Add the OnDispose (Virtual) method to ViewModelBase, which is called in the Dispose () method for the VM. Each ViewModel of your application must override this OnDispose method, in which you will unsubscribe from your events. Sort of -
    OnDispose () {base.Dispose (); UnsubscribeEvent (abcEventSubscribername); }

the 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 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; } } } } 
+3
source

You can force the View to notify the ViewModel when it is unloaded (or in the case of a window when it is closed). Then, in the Unloaded / Closed handler in the ViewModel, you can unsubscribe. So I do it in my application.

+2
source

Source: https://habr.com/ru/post/886896/


All Articles