WPF MVVM为什么使用ContentControl + DataTemplate视图而不是直接的XAML窗口视图?


83

为什么这个?

MainWindow.xaml:

<Window x:Class="MVVMProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <ContentControl Content="{Binding}"/>
    </Grid>
</Window>

将您的ExampleView.xaml设置为:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vms="clr-namespace:MVVMProject.ViewModels">
    <DataTemplate DataType="{x:Type vms:ExampleVM}" >
        <Grid>
            <ActualContent/>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

并创建如下窗口:

public partial class App : Application {

    protected override void OnStartup(StartupEventArgs e) {

        base.OnStartup(e);

        MainWindow app = new MainWindow();
        ExampleVM context = new ExampleVM();
        app.DataContext = context;
        app.Show();
    }
}

什么时候可以这样做?

App.xaml :(设置启动窗口/视图)

<Application x:Class="MVVMProject.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="ExampleView.xaml">
</Application>

ExampleView.xaml :(不是ResourceDictionary的窗口)

<Window x:Class="MVVMProject.ExampleView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vms="clr-namespace:MVVMProject.ViewModels">
    >
    <Window.DataContext>
        <vms:ExampleVM />
    </Window.DataContext>

    <Grid>
        <ActualContent/>
    </Grid>
</Window>

本质上是“以数据视图形式查看”(VaD)与“以窗口形式查看”(VaW)

这是我对比较的理解:

  • VaD:让您在不关闭窗口的情况下切换视图。(这对于我的项目而言是不可取的)
  • VaD:VM对View绝对一无所知,而在VaW中(仅)它必须能够在打开另一个窗口时实例化它
  • VaW:我实际上可以在Designer中看到我的xaml渲染(至少在当前设置中我不能使用VaD)
  • VaW:直观地与打开和关闭窗口一起工作;每个窗口都有一个对应的View(和ViewModel)
  • VaD:ViewModel可以通过属性传递初始窗口的宽度,高度,可缩放性等(而在VaW中,它们直接在Window中设置)
  • VaW:可以设置FocusManager.FocusedElement(不确定如何在VaD中使用)
  • VaW:文件较少,因为我的窗口类型(例如功能区,对话框)已合并到其视图中

那么这是怎么回事?我不能仅在XAML中构建窗口,通过VM的属性干净地访问其数据并完成操作吗?后面的代码是相同的(几乎为零)。

我正在努力理解为什么我应该将所有View内容改组为ResourceDictionary。


2
这样思考:ViewModels应该在Windows或UserControls中显示。Poco将显示在DataTemplates中。:)
开发刺猬

Answers:


129

人们DataTemplates想根据ViewModel动态切换视图时使用这种方式:

<Window>
    <Window.Resources>
       <DataTemplate DataType="{x:Type local:VM1}">
          <!-- View 1 Here -->
       </DataTemplate>

       <DataTemplate DataType="{x:Type local:VM2}">
          <!-- View 2 here -->
       </DataTemplate>
    </Window.Resources>

    <ContentPresenter Content="{Binding}"/>

</Window>

所以,

如果Window.DataContext是的实例VM1View1则将显示,

而如果

Window.DataContext是的实例VM2View2则将显示。

当然,如果只需要1个View且永不更改,则完全没有意义。


8

由于在VaD中,视图模型对视图一无所知,因此您可以构建一个完全由视图模型组成且不包含视图的功能齐全的应用程序。这导致编写可以完全由代码驱动的应用程序的可能性。这进而导致无需GUI即可执行集成测试的可能性。众所周知,通过GUI进行集成测试非常脆弱-而通过视图模型进行的测试应该更可靠。


5

根据我的个人经验:两种工作模型都是可行的,具体取决于您想要的内容以及应用程序的要求。背后的想法VaD是清除内容和容器。如果实施VaD,则可以在显示任何此类项目时使用此模板(默认情况下)。您可以在ItemsControls(列表,列表视图,网格等)和ContentControls仅进行绑定的情况下使用它。就像您说的那样,VaD可以在不关闭和打开新窗口的情况下切换窗口的内容。另外,您可以使用定义视图UserControls,然后控制焦点集中的元素,还可以管理后面的代码。因此,您的数据模板可能是这样的:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vms="clr-namespace:MVVMProject.ViewModels">
<DataTemplate DataType="{x:Type vms:ExampleVM}" >
    <CustomUserControl A="{Binding A}" B="{Binding B}" DataContext="{Binding}" .../>
</DataTemplate>

您还UserControl可以设置依赖项属性,这可以简化工作,因为允许绑定和解耦应用程序。

但是当然,如​​果您的应用程序不需要动态切换内容,则可以将其VaW用于主窗口或任何其他窗口。实际上,您可以同时使用VaWVaD。最后一个可用于应用程序中的内部项目,不需要窗口。您应根据应用程序要求以及开发该应用程序的时间选择适合自己的方案。希望这种个人经验对您有帮助...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.