取消订阅 ViewModel 中的 EventAggregator 事件

发布于 2024-11-04 02:24:33 字数 773 浏览 1 评论 0原文

我开始将 WPF 与 PRISM 和 MVVM 结合使用。我面临的一个问题是,我找不到一个好地方/最佳实践来取消订阅以前在 ViewModel 中订阅的 EventAggregator 事件。以下解决方案 - 在析构函数中调用 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)
    {
    }
}

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.Current.GetInstance<IEventAggregator>();
        eventAggregator.GetEvent<SeriesSelectionChangedEvent>().Unsubscribe(OnSeriesSelectionChanged);
    }

    void OnSeriesSelectionChanged(SeriesSelectionChangedEventArgs e)
    {
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南街九尾狐 2024-11-11 02:24:33

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

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

另一种方法是使用命令。您的模型公开命令,视图关闭时必须调用该命令。 ViewModel 可以使用命令处理程序来取消订阅。

顺便说一句,如果您担心 EventAggregator 会保存您的 ViewModel,这不是问题,因为 Prism 的 EventAggregator 使用弱引用。

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.

久夏青 2024-11-11 02:24:33

好吧,不久前,我也遇到了同样的问题。这就是我们所做的(WPF 应用程序)。

  1. 创建一个新的基类 - DisposableUserControl:UserControl、IDisposable。这将包含处理用户控件的逻辑。代码添加在最后。
  2. 将应用程序中的所有用户控件替换为 DisposableUserControl。就像<应用程序:DisposableUserControl ....> < /app.DisposableUserControl>
  3. 在 ViewModelBase 中添加一个 OnDispose 方法(虚拟),该方法在 VM 的 Dispose () 方法中调用。应用程序的每个 ViewModel 都应重写此 OnDispose 方法,您将在其中取消订阅事件。类似的东西-
    OnDispose() { 基.Dispose();取消订阅事件(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;
                }
            }
        }
    }

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;
                }
            }
        }
    }
哥,最终变帅啦 2024-11-11 02:24:33

您可以让 View 在卸载时通知 ViewModel(或者在窗口关闭时通知 ViewModel)。然后,在 ViewModel 的 Unloaded/Closed 处理程序中,您可以取消订阅。这就是我在我的应用程序中所做的方式。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文