2011-04-28 183 views
6

我开始使用带有PRISM和MVVM的WPF。我面临的一个问题是,我无法找到一个好的地方/最佳做法来取消订阅以前在ViewModel中订阅的EventAggregator事件。以下解决方案 - 在析构函数中调用Unsubscribe - 太迟了。它只是运行下一个垃圾收集。取消订阅ViewModels中的EventAggregator事件

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

这取决于你!如果您的应用程序可以在不再需要时通知ViewModel,那么您应该在那里取消订阅。

例如,在我们的项目中,我们有IViewDisposeService。如果视图(或其模型)需要确定性定稿,则在展示时将其自身注册到IViewDisposeService中。然后,核心使用相同的服务通知注册视图何时从区域中删除。

另一种方法是使用命令。你的模型暴露了视图在关闭时必须调用的命令。 ViewModel可以使用命令处理程序来取消订阅。顺便说一句,如果你担心EventAggregator会容纳你的ViewModel,这不是问题,因为Prism的EventAggregator使用弱引用。

+2

注册事件时,您还可以选择强引用。 – 2011-04-29 06:46:56

+0

这取决于我 - 这就是我所怀疑的。我认为你的第二个建议 - 通过视图触发命令 - 符合我的需要。很好的答案! – 2011-04-29 07:02:13

+0

@Daniel:哎呀,我忘了它。这是很久以前,当我在我的项目中添加最后一个事件:)) – 2011-04-29 07:44:21

3

好吧,有时候我也面临同样的问题。这就是我们所做的(WPF App)。

  1. 创建一个新的基类 - DisposableUserControl:用户控件,IDisposable接口。这将包含处理用户控件的逻辑。代码添加到最后。
  2. 用DisposableUserControl替换应用程序中的所有用户控件。像< app:DisposableUserControl ....> </app.DisposableUserControl>
  3. 在ViewModelBase中添加OnDispose方法(虚拟),该方法在VM的Dispose()方法中调用。您的应用的每个ViewModel应该重写此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

你可以有查看通知视图模型卸载时(或在窗口的情况下,当它被关闭)。然后在ViewModel中的Unloaded/Closed处理程序中,您可以取消订阅。这是我在应用程序中执行的方式。

+0

这实质上与Marat的建议类似。我认为这是要走的路。 – 2011-04-29 07:03:22

+0

我使用Cinch v2作为MVVM框架。它会自动添加装载/卸载等事件 – 2011-04-29 07:05:22