您是否考虑过在 ViewModel 和 View 之间使用类似事件的交互来避免在 ViewModel 中保留对 View 的引用?
在 ViewModel 中,我将创建一个 Action 类型的属性,并将其命名为 ThisIsCalledEvent;
#region ThisIsCalledEvent
private Action m_ThisIsCalledEvent;
public Action ThisIsCalledEvent
{
get
{
return m_ThisIsCalledEvent;
}
set
{
if (m_ThisIsCalledEvent != value)
{
m_ThisIsCalledEvent = value;
OnPropertyChanged(nameof(ThisIsCalledEvent));
}
}
}
#endregion
然后,在MyUserControl中,为DataContextChanged事件添加事件回调;
this.DataContextChanged += MyUserControl_DataContextChanged; 在 CS 构造函数中,或
DataContextChanged="MyUserControl_DataContextChanged" 在 XAML 构造函数中。
现在,在事件回调中,您可以为 ViewModel 的ThisIsCalledEvent 属性设置Action;
private void MyUserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
MyUserControlViewModel vm = DataContext as MyUserControlViewModel; //Get the ViewModel from the View's DataContext
if(vm == null)
return;
vm.ThisIsCalledEvent = delegate () { ThisIsCalled(); }; //When the action is invoked, call the desired function
}
现在,回到 ViewModel,调用您只需将方法的主体更改为;
public void MethodThatForwardsCalls()
{
this.ThisIsCalledEvent?.Invoke(); //Invoke the Action, if it exists, that has been set by the View
}
这样,您永远不会在 ViewModel 中保留 View 的实例,并且每次从 ViewModel 实例化新视图时,它都会设置 Action 回调。
编辑
正如 Jürgen Röhr 在 cmets 中所建议的,在 DataContextChanged 事件回调中,您可以使用 args.NewValue 绑定到新的 DataContext。此外,如果您将代理注册到Action 属性而不是设置它,您可以使用args.OldValue 将其从之前的DataContext 中取消注册。