为什么使用 ContentControl + DataTemplate 视图而不是直接的 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();
}
}

什么时候可以这样做呢?

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>

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: VM 对视图一无所知,而在 VaW 中,它(仅)必须能够在打开另一个窗口时实例化它
  • VaW: 我实际上可以看到我的 xaml 在 Designer 中呈现(我不能 至少在我目前的设置)
  • 直观地说 打开和关闭窗口; 每个窗口都有一个对应的视图 (及 ViewModel)
  • 视图模型可以通过属性传递初始窗口宽度、高度、可调大小等信息(而在视图模型中,它们直接在窗口中设置)
  • 可以设置 FocusManager.FocusedElement (不确定在 VaD 中如何设置)
  • VaW: 更少的文件,因为我的窗口类型(如 Ribbon,Dialog)被合并到他们的视图中

这是怎么回事?我能不能只用 XAML 构建窗口,通过 VM 的属性清晰地访问它们的数据,然后就完事了?代码隐藏是相同的(几乎为零)。

我很难理解为什么我要把所有的查看内容都放到 ResourceDictionary 中。

92287 次浏览

People use DataTemplates that way when they want to dynamically switch Views depending on the 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>

So,

if Window.DataContext is an instance of VM1, then View1 will be displayed,

and if

Window.DataContext is an instance of VM2, then View2 will be displayed.

Granted, it makes no sense at all if only 1 View is expected, and never changed.

From my personal experience: Both work models are aviables, depending of what you want, and depending of the application requirements. The idea behind VaD is decopling the content, and the container. If you implement VaD you can use this template (by default) when ever you show any item of this type. You can use it in ItemsControls (lists, listviews, grids, etc) and in ContentControls only making bindings. Like you said, VaD works for switching the window's content with out closing and opening a new. Also you can define the view using UserControls, then you take control if focused elements, and also you can manage code behind. So, your data template may be like this:

<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>

You also in an UserControl may set dependency properties, thats make easier the job, because allow bindings and decoupling the app.

But of course, if you app doesn't require dynamically content switching, it is fine to use VaW for the main window, or any other window. In fact, you can use both VaW and VaD. This last one can be used for inner items in the app, that doesn't require windows. You shoose what is better for you, depending of application requirements, and the time aviable for developing the app. Hope this personal experience helps...

Since in VaD the view models know nothing about the views, you can build a fully functioning application entirely made up of view models only and no views. This leads to the possibility of writing an application that can be driven entirely by code. This in turn leads to the possibility of performing integration testing without the GUI. Integration testing through the GUI is notoriously fragile - while testing through view models should be more robust.