一般来说,您应该在 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()
}
这与布莱恩的回答基本相同,我喜欢并赞成。这只是更通用,你不绑定到 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();
}
}