我们用Prism开始了一个WPF项目,我提出了一个问题:
有时在ViewModel中,我们会注册一些事件或启动我们必须在关闭之前停止的服务。这意味着当我关闭应用程序时,我需要释放我在ViewModel中获取的资源。然后Dispose会有很多感官。
目前我正在使用Prism的ViewModelLocator.Autowire = True
,我当时认为当不再需要View时,如果需要它会处理它。
我有两个案例:
RegionManager.RequestNavigate("RegionName", "RegionUri")
)我的问题是:处理这些ViewModel的正确方法是什么?我可以看到多种方式,但我不确定哪一种是正确的。
答案 0 :(得分:2)
我很一般,你应该在Unloaded活动中进行清理登录。
我通过在View的Loaded resp Unloaded事件中调用ViewModel上的Activate和Deactivate方法解决了这个问题。
interface IViewModelLifeCycle
{
void Activate();
void Deactivate();
}
public class MyComponentViewModel: BindableBase, IViewModelLifeCycle {
public void Activate(){}
public void Deactivate()
}
这基本上与Brian's answer中的原则相同,我喜欢和赞成。这只是更通用的,你不依赖于RegionManager(我不喜欢RegionManager)
<强> [可选] 强>
为了让它更舒服,我创建了附加到视图的行为,而不是在代码后面编写一些代码:
<local:MyComponentView DataContext="{Binding MyComponentViewModel}"
local:ViewModelLifeCycleBehavior.ActivateOnLoad="True" />
<Style x:Key="PageStyle" TargetType="Page">
<Setter Property="local:ViewModelLifeCycleBehavior.ActivateOnLoad" Value="True" />
</Style>
行为实现有点繁琐,但它实际上是非常简单的模式。在PropertyChanged回调中,附加到FrameworkElements事件。
public static class ViewModelLifeCycleBehavior
{
public static readonly DependencyProperty ActivateOnLoadProperty = DependencyProperty.RegisterAttached("ActivateOnLoad", typeof (bool), typeof (ViewModelLifeCycleBehavior),
new PropertyMetadata(ActivateOnLoadPropertyChanged));
public static void SetActivateOnLoad(FrameworkElement element, bool value)
{
element.SetValue(ActivateOnLoadProperty, value);
}
public static bool GetActivateOnLoad(FrameworkElement element)
{
return (bool)element.GetValue(ActivateOnLoadProperty);
}
private static void ActivateOnLoadPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (DesignerProperties.GetIsInDesignMode(obj)) return;
var element = (FrameworkElement)obj;
element.Loaded -= ElementLoaded;
element.Unloaded -= ElementUnloaded;
if ((bool) args.NewValue == true)
{
element.Loaded += ElementLoaded;
element.Unloaded += ElementUnloaded;
}
}
static void ElementLoaded(object sender, RoutedEventArgs e)
{
var element = (FrameworkElement) sender;
var viewModel = (IViewModelLifeCycle) element.DataContext;
if (viewModel == null)
{
DependencyPropertyChangedEventHandler dataContextChanged = null;
dataContextChanged = (o, _e) =>
{
ElementLoaded(sender, e);
element.DataContextChanged -= dataContextChanged;
};
element.DataContextChanged += dataContextChanged;
}
else if (element.ActualHeight > 0 && element.ActualWidth > 0) //to avoid activating twice since loaded event is called twice on TabItems' subtrees
{
viewModel.Activate(null);
}
}
private static void ElementUnloaded(object sender, RoutedEventArgs e)
{
var element = (FrameworkElement)sender;
var viewModel = (IViewModelLifeCycle)element.DataContext;
viewModel.Deactivate();
}
}
答案 1 :(得分:1)
由于您正在使用区域导航,因此我建议您使用一种简单的区域行为,只要从区域中删除视图,就会调用您的接口方法。我在Pluralsigh课程中展示了这个例子:https://www.pluralsight.com/courses/prism-problems-solutions