WPF MVVM:如何更新Usercontrol数据

时间:2018-04-15 15:26:51

标签: c# wpf mvvm mvvm-light

从WPF开始,我喜欢MVVM模式,我有一个ViewModel定位器,因为我已经习惯了IoC的使用。但是大多数博客/文章都说Usercontrol不应该有ViewModel。这是有道理的,但后来我无法完全了解如何更新其数据。

例如,假设我有一个Usercontrol(UC),它显示一个包含硬件设备数据的图表。我已经实现了“IProvideGraphData”接口并准备就绪。但是如何将它注入我的Usercontrol?

我更喜欢这个在Usercontrol构造函数中,但由于View没有使用IoC(通过ViewModel定位器)调用Usercontrol,我无法理解如何以干净精确的方式完成这个操作......

思想?

1 个答案:

答案 0 :(得分:2)

不确定您正在阅读哪些博客和文章,但UserControls绝对可以拥有自己的ViewModel(VM)。他们总是吗?没有!他们曾经吗?绝对!这一切都取决于用户控件的用途。

如果要将主视图分解为主视图和子视图(即窗口包含UserControls)以便具有良好定义的层次结构,则ViewModel也应遵循相同的层次结构。这意味着,您的主窗口具有其DataContext的主虚拟机,其中主虚拟机将子虚拟机公开为属性,子视图(即UC)将这些子虚拟机属性用于其DataContext。

这里继承的ViewModelBase实现了INotifyPropertyChanged接口。主VM看起来像这样:

public class MasterViewModel : ViewModelBase
{
    public MasterViewModel()
    {
        ChildVM = new ChildVMType();
    }

    private ChildVMType childVM;
    public ChildVMType ChildVM
    {
        get { return childVM; }
        set { SetProperty(ref childVM, value); }
    }
    ...
}

Master View / ViewModel将使用View-First Construction主体,您可以在XAML(或您喜欢的任何其他方式)中明确地实例化主VM。关键是,View实例化了ViewModel。

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

另一方面,子VM由Master ViewModel实例化(参见上面的VM),通常在构造函数中,遵循ViewModel-First Construction Principal。

要将子VM注入用户控件,您可以在主视图(即主窗口)的某处执行类似的操作:

<ContentControl>
    <local:MyChildUCview DataContext="{Binding ChildVM}"/>
</ContentControl> 

其中ChildVM是在Master ViewModel上公开的属性(见上文)。

还有很多其他方法可以解决这个问题,但这个想法是一样的。

您应该实现的目标是Child VM负责处理主VM不关心的所有逻辑。这将使关注点更加分离,并将极大地提高可维护性和可扩展性。

要允许主虚拟机和子虚拟机之间进行双向通信,您可以使用事件。例如,您的子VM具有您的主VM订阅的事件。当Master需要知道的子VM中发生某些事情时,Child会引发事件并将所需的参数传递给Master。主人当然可以直接与孩子说话,因为它是自己的财产。

如果你认真学习这个,我强烈建议你观看Pluralsight的课程,即Brian Noyes的"WPF MVVM in Depth"。您可以注册免费试用,这应该足以完成本课程。