在MVVM中使用dispose取消订阅事件

33 浏览
0 Comments

在MVVM中使用dispose取消订阅事件

实际上,我正在尝试通过从我的ViewModel触发事件来关闭我的窗口。 一切都很好,但我知道必须取消订阅我的事件以避免内存泄漏。 因此,我实现了IDisposable接口,并在Dispose方法中取消订阅事件。

下面是我的代码:

public partial class MainWindow : Window, IDisposable
{
    private MainViewModel viewModel;
    public MainWindow()
    {
        InitializeComponent();
        DataContext = viewModel =  new MainViewModel();
        this.viewModel.RequestClose += CloseWindow;
    }
    void CloseWindow(object sender, EventArgs e)
    {
        this.Close();
    }
    public void Dispose()
    {
        ////here we need to unsubscribe the event
        this.viewModel.RequestClose -= this.CloseWindow;
    }
}

我需要知道的是:

  1. 那个代码是正确的吗?
  2. GC何时调用并执行dispose方法?
  3. 是否有更好的方法来做这件事?
admin 更改状态以发布 2023年5月23日
0
0 Comments

只有在源和处理程序具有不同的生命周期时,才需要取消订阅事件,否则它们同时离开范围并一起被垃圾回收。

因此,在这种情况下,不需要使用IDisposable。无论如何,如果实现IDisposable,您需要显式调用它,否则您无法控制它何时被调用。

0
0 Comments

但我知道,我必须取消订阅我的事件以避免内存泄漏。

内存泄漏会在短暂存在的对象订阅了长期存在的对象(或静态事件),并且后来没有取消订阅时发生(例如,请参见 这个 答案)。我想,这不是你的情况。

当GC被调用并执行dispose方法时

GC不会调用IDisposable.Dispose(例如,请参见这个答案)。从来不会。
如果你没有任何代码显式地调用MainWindow.Dispose,它将永远不会被调用。

有没有更好的方法来做这样的事情?

我会避免使用IDisposable和事件。我认为这里的附加行为更方便(至少,这是可重用的):

public static class WindowClosingBehavior
{
        public static bool GetIsClosingInitiated(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsClosingInitiatedProperty);
        }
        public static void SetIsClosingInitiated(DependencyObject obj, bool value)
        {
            obj.SetValue(IsClosingInitiatedProperty, value);
        }
        public static readonly DependencyProperty IsClosingInitiatedProperty = DependencyProperty.RegisterAttached(
            "IsClosingInitiated", 
            typeof(bool), 
            typeof(WindowClosingBehavior),
            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsClosingInitiatedChanged));
        private static void IsClosingInitiatedChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {
            var window = target as Window;
            if (window != null && (bool)e.NewValue)
            {
                window.Close();
            }
        }
}

窗口XAML中的某个地方:

behaviors:WindowClosingBehavior.IsClosingInitiated="{Binding IsClosingInitiated}"

其中IsClosingInitiated是视图模型中的属性:

public class SomeViewModel
{
     // ...
     private void Foo()
     {
         // ...
         IsClosingInitiated = true;
     }
}

0