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