不确定您正在阅读哪些博客和文章,但 UserControl 绝对可以并且确实拥有自己的 ViewModel (VM)。他们总是吗?不!他们有吗?绝对地!这完全取决于用户控件的用途。
如果您要将主视图分解为主视图和子视图(即窗口包含用户控件)以具有明确定义的层次结构,则视图模型也应遵循相同的层次结构。意思是,您的主窗口具有用于其 DataContext 的主 VM,其中主 VM 将子 VM 公开为属性,而子视图(即 UC)将这些子 VM 属性用于其数据上下文。
这里继承的ViewModelBase实现了INotifyPropertyChanged接口。主虚拟机将如下所示:
public class MasterViewModel : ViewModelBase
{
public MasterViewModel()
{
ChildVM = new ChildVMType();
}
private ChildVMType childVM;
public ChildVMType ChildVM
{
get { return childVM; }
set { SetProperty(ref childVM, value); }
}
...
}
主视图/视图模型将使用视图优先构造主体,您可以在 XAML 中以声明方式(或您喜欢的任何其他方式)实例化主 VM。关键是,View 实例化了 ViewModel。
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
另一方面,子 VM 由主 ViewModel(参见上面的 VM)实例化,通常在构造函数中,遵循 ViewModel-First 构造主体。
要将子虚拟机注入用户控件,您可以在主视图(即主窗口)的某处执行以下操作:
<ContentControl>
<local:MyChildUCview DataContext="{Binding ChildVM}"/>
</ContentControl>
其中 ChildVM 是在 Master ViewModel 上公开的属性(见上文)。
还有很多其他的方法可以把它连接起来,但想法是一样的。
您应该实现的目标是子 VM 负责处理主 VM 不关心的所有逻辑。这将允许更大程度地分离关注点,并极大地提高可维护性和可扩展性。
要允许主虚拟机和子虚拟机之间进行双向通信,您可以使用事件。例如,您的子 VM 具有您的主 VM 订阅的事件。当子 VM 中发生了 Master 需要知道的事情时,Child 会引发事件并将所需的参数传递给 Master。主人当然可以直接对孩子说话,因为它是它自己的财产。
如果您认真学习这一点,我强烈建议您观看有关 Pluralsight 的课程,即 Brian Noyes 的 "WPF MVVM in Depth"。您可以注册免费试用,这应该足以完成本课程。