MvvmLight : 如何取消订阅 "RaisePropertychanged" 事件

MvvmLight : How to unsubscribe "RaisePropertychanged" Event

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

我的申请:

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"?

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

编辑:代码

编辑二

请在我的 github 上找到出现问题的完整项目,而不是放一些代码。

https://github.com/damgot/MvvmLightProblemExample

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

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

Starting
Creating NewViewModel

然后,当我点击 NewView 菜单时,新视图打开 :

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

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

似乎没问题,因为我在 "MyBool"

上绑定了 2 个单选按钮

现在如果我 select "MyBool is false" 单选按钮 :

并在输出中:

MyBool Set call + RaiseProperty
MyBool Get call
MyBool Get call

还是不错的。

现在,如果我关闭 NewView,然后再次打开它,然后 select "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

等等...

如你所见,"Get"调用我的属性,增加每组我重新打开视图

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

正如我在评论中所说,我的项目并不孤单,解决方案涉及我无法编辑的其他项目。所以我不能简单地压制 "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 的​​订阅都被重置。

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

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

在我的 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;
}

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

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

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

而且效果很好。