【问题标题】:MvvmLight : How to unsubscribe "RaisePropertychanged" EventMvvmLight:如何取消订阅“RaisePropertychanged”事件
【发布时间】:2020-02-14 12:54:14
【问题描述】:

我在使用 MvvmLight 的 WPF 应用程序中遇到问题。

我的申请:

  • 我有一个带菜单的 MainView,每个 MenuItem 都会打开一个新视图(每个 menuitem 都不同)。
  • 每个 MenuItem 都绑定到我的 MainViewModel 的 RelayCommand
  • 在我的 MainViewModel 中,RelayCommand 只需对 MainView 执行 Messenger.Default.Send(this, "ShowMyView")
  • 在我的 MainView 中,我在消息“ShowMyView”上注册,操作是:

var v = new MyView(); v.Owner = this; v.ShowDialog(); Messenger.Default.Unregister(v);

这个新视图 (MyView) 绑定在包含属性的视图模型 (MyViewModel) 上。 此视图的元素(文本框、单选按钮等)绑定到这些属性。

当我关闭“MyView”时,它已被释放,我回到主视图,但“MyViewModel”仍然存在。

问题:

当我第一次打开“MyView”时,绑定工作正常,如果“MyViewModel”设置了一个属性,则调用RaisePropertyChanged,然后调用该属性的“get”一次。

但是如果我打开和关闭我的视图 20 次,在第 20 次,当调用 RaisePropertyChanged 时,该属性的 get 是调用 20 次!

问题:

那么当我关闭视图时如何取消订阅这些“RaisePropertyChanged”?

希望你很清楚,抱歉我的英语不好。

编辑:使用代码

编辑 BIS

不要放部分代码,请在我的github上找到一个出现问题的完整项目。

https://github.com/damgot/MvvmLightProblemExample

当我运行应用程序时,MainWindow 启动:

你可以在调试输出中看到:

Starting
Creating NewViewModel

然后,当我点击 NewView Menu 时,newview 打开:

您可以在调试输出中看到:

Initialize NewViewModel and set MyBool to true
MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call

看起来不错,因为我在“MyBool”上绑定了 2 个单选按钮

现在如果我选择“MyBool is false”单选按钮:

在输出中:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call

还是不错的。

现在,如果我关闭 NewView,然后再次打开它,并选择“MyBool is false”单选按钮,输出是:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call

然后再一次,输出是:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call

再一次:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call
MyBool Get call

等等……

如您所见,“获取”调用我的属性,增加我重新打开视图的每个团队

【问题讨论】:

  • 请分享您的问题的代码示例。
  • 如果在ShowDialog()之后设置v.Owner = null会怎样?
  • 您使用的是哪个版本的 mvvmlight,您的解决方案针对的是什么框架?您的命令 using 语句,最后是否有 WPF?
  • 我添加了一些代码。我使用 nuget 包“MvvmLightLibs v5.3.0”和应用程序目标 .NET Framework 4.5.2。是的,它是一个 WPF 应用程序
  • 而不是使用 viewmodellocator。尝试使 MyViewModel 成为 myview 的私有成员。在 xaml 中实例化它。你的问题解决了吗?

标签: c# .net wpf mvvm-light


【解决方案1】:

我找到了一个解决方案,但它是一个丑陋的解决方案。

正如我在评论中所说,我的项目并不孤单,解决方案涉及我无法编辑的其他项目。所以我不能简单地抑制“ViewModelLocator”。

所以要解决我的问题,在我的 ViewModelLocator 中,在我的 ViewModels 属性中,而不是这样做:

public NewViewModel NewView
{
    get
    {
        var vm = ServiceLocator.Current.GetInstance<NewViewModel>();
        vm.Initialize();
        return vm;
    }
}

我这样做:

public NewViewModel NewView
{
    get
    {
        SimpleIoc.Default.Unregister<NewViewModel>();
        SimpleIoc.Default.Register<NewViewModel>(true);
        var vm = ServiceLocator.Current.GetInstance<NewViewModel>();
        vm.Initialize();
        return vm;
    }
}

每次我调用 ViewModel(所以当我打开视图时),模型都是未注册的,然后是已注册的。它强制重新创建 ViewModel,因此对 PropertyChanged 的​​所有订阅都将被重置。

我不会将此解决方案设置为好的解决方案,因为我认为此解决方案不是很漂亮。但它有效,并且使用的内存似乎没有增加。

【讨论】:

    【解决方案2】:

    我找到了另一个解决方案,比我发布的第一个解决方案更漂亮。

    在我的 ViewModelLocator 中,我删除了每个视图模型属性。 我已经创建了这个静态函数:

    public static T GetViewModelInstance<T>(Window w)
    {
        var uniqueKey = System.Guid.NewGuid().ToString();
        T VMInstance = ServiceLocator.Current.GetInstance<T>(uniqueKey);
        w.Closed += (sender, args) => SimpleIoc.Default.Unregister(uniqueKey);
        return VMInstance;
    }
    

    所以,如您所见,我没有返回 ViewModel,而是返回它的一个新实例(带有 uniqueKey 令牌)。 并且我在调用视图 Closed 事件上注册以取消注册创建的 VM 实例。

    我不再在 xaml 中定义 DataContext 而是在 xaml.cs 中,在构造函数中,我将 DataContext 设置如下:

    DataContext = ViewModelLocator.GetViewModelInstance<NewViewModel>(this);
    

    而且效果很好。

    【讨论】:

      猜你喜欢
      • 2017-02-12
      • 2013-04-15
      • 1970-01-01
      • 2018-01-05
      • 2017-07-16
      • 2014-02-15
      • 1970-01-01
      • 2017-04-25
      • 1970-01-01
      相关资源
      最近更新 更多