在Prism/Composite MVVM WPF应用程序中使视图模型激活感知

在Prism/Composite MVVM WPF应用程序中使视图模型激活感知,wpf,mvvm,prism,eventaggregator,Wpf,Mvvm,Prism,Eventaggregator,在我的MVVMC应用程序中,我有一个包含多个步骤的流程,基本上是一个向导 我的控制器解析我的外部视图(称之为WizardView),并将其添加到主区域 WizardView包含一个面包屑轨迹,用于显示向导的进度,以及一个子区域,用于将其他视图加载到该子区域(称为WizardRegion)Step1View是加载到WizardRegion的第一个视图 每个视图都使用Unity容器将其ViewModel注入构造函数 WizardViewModel订阅步骤视图模型发布的多个事件聚合事件 当每个步骤完成

在我的MVVMC应用程序中,我有一个包含多个步骤的流程,基本上是一个向导

我的控制器解析我的外部视图(称之为
WizardView
),并将其添加到主区域

WizardView
包含一个面包屑轨迹,用于显示向导的进度,以及一个子区域,用于将其他视图加载到该子区域(称为
WizardRegion
Step1View
是加载到
WizardRegion
的第一个视图

每个视图都使用Unity容器将其ViewModel注入构造函数

WizardViewModel
订阅步骤视图模型发布的多个事件聚合事件

当每个步骤完成时,视图模型会发布一个事件,
WizardViewModel
使用该事件来存储状态,这意味着
WizardViewModel
会在我们进行过程中从每个步骤收集数据。step ViewModel还调用控制器将下一步加载到
向导区域

在最后一步中,
WizardViewModel
保存向导的结果,
MainRegion
被导航回其他屏幕

下次进入向导时,我们将创建所有视图和视图模型的新实例,但来自上一个向导的事件订阅仍然存在

如何使视图模型意识到它们已被取消激活,以便取消订阅活动


另一个选项是取消订阅事件处理程序中的事件。这可能会起作用,但当我退出向导并需要再次重新订阅事件时,会增加复杂性。

如果您谈论的是Prism EventAggregator-您可以将
KeepSubscriberReferenceal
参数设置为
false
,这样它将在引擎盖下使用弱引用,因此所有内容都将被“取消订阅”当对象将“死亡”时,由GC自动执行

否则,您必须自己明确取消订阅:

fundAddedEvent.Unsubscribe(FundAddedEventHandler);

解决方案是在我的视图模型中实现
Microsoft.Practices.Prism.IActiveAware

public bool IsActive
{
    get { return _isActive; }
    set
    {
        if (_isActive != value)
        {
            _isActive = value;
            DoActiveChangedWork(value);
        }
    }
}

public event EventHandler IsActiveChanged;

也可以在视图中实现这一点,但这不是一个要求

我使用的是Prism,很抱歉我添加了标签,但问题中没有明确说明。我的印象是默认行为是使用弱引用。keepSubscriberReferenceAlive标志没有任何效果。订阅的实例可能不再被引用,但它未被垃圾收集,因此事件仍会再次激发。我需要找到一种方法来取消激活视图模型。看起来您正在使用Unity for DI。这是真的吗?如果是这样,您是将类注册为实例还是单例?是的,我使用的是Unity。我正在将视图和视图模型注册为实例。它们最初注册为单例,但在重新进入向导时会导致错误。如果我重新将视图和视图模型注册为singlton,那么我仍然需要在视图模型中处理某种类型的取消激活,以便在下次向导中重置状态。我不知道视图和视图模型的推荐生存期是多少。生存期对应用程序来说是有意义的。我根据逻辑使用这两种方法。实例视图模型在“卸载”事件后是否仍处理该事件?它的~finalizer()启动了吗?我没有一个终结器,我会试一试并让你知道。在你的虚拟机上实现接口。例如,我认为它不必同时在视图和虚拟机中实现。在虚拟机中实现它就足够了。IsActive由RegionBehavior设置。您只需检查该值是否为false,然后取消订阅您的活动。。。只是说:)如果我错了,请纠正我,我还想说,因为不需要订阅者,所以没有必要触发ISACTIVECHANGE事件。@ViktorLaCroix我猜可能是这样,但还没有测试它。我也不明白他们为什么使用
=delegate{}事件定义末尾的语法。我应该用一个更好的代码示例来清理这个答案,并在有时间的时候删除链接。
public bool IsActive
{
    get { return _isActive; }
    set
    {
        if (_isActive != value)
        {
            _isActive = value;
            DoActiveChangedWork(value);
        }
    }
}

public event EventHandler IsActiveChanged;