WPF MVVM为什么使用ContentControl + DataTemplate Views而不是直观的XAML Window Views?

我有一个关于WPF中的MVVM的问题,正在驱动我batty。

为什么要这样做:?

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> 

并像这样创build窗口:

 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)

这里是我对比较的理解:(注意我使用VS 2008,所以我缺乏Blendability和/或其他的东西)

  • VaD:可以在不closures窗口的情况下切换视图。 (这是我的项目不可取的)
  • VaD:VM对视图一无所知,而在VaW中它(仅)必须能够在打开另一个窗口时对其进行实例化
  • VaW:我实际上可以在Designer中看到我的xaml(我不能用VaD,至less在我目前的设置中)
  • VaW:直观的打开和closures窗口; 每个窗口都有一个对应的View(和ViewModel)
  • VaD:ViewModel可以通过属性传递初始窗口的宽度,高度,可调整性等(而VaW则直接设置在Window中)
  • VaW:可以设置FocusManager.FocusedElement(不知道如何在VaD中)
  • VaW:较less的文件,因为我的窗口types(例如function区,对话框)被纳入他们的意见

那么这里发生了什么? 我不能只用XAML构build我的窗口,通过VM的属性干净地访问他们的数据,并完成它? 代码隐藏是相同的(几乎为零)。 我很努力地理解为什么我应该把所有的View东西都打包到一个ResourceDictionary中。 (但我不想做错 ;-))


它甚至重要吗? 有什么我错过了吗? 非常感谢您的阅读。 :o


感谢Rachel Lim和Nick Polyak对MVVM的深入理解

编辑:小stream量更改

人们使用DataTemplates方式,当他们想dynamic地切换视图取决于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.DataContextVM1一个实例,则将显示View1

而如果

Window.DataContextVM2一个实例,那么将显示View2

当然,如果只有1个视图是预料不到的,那就没有意义了。

我希望这是足够清楚的:P

由于在VaD中,视图模型对视图一无所知,因此可以构build一个完全由视图模型组成的完全正常运行的应用程序,而不是视图。 这导致编写可完全由代码驱动的应用程序的可能性。 这反过来导致在没有GUI的情况下执行集成testing的可能性。 通过GUI进行集成testing非常脆弱 – 而通过视图模型进行testing应该更加强大。

从我的个人经验来看:这两种工作模式都是可行的,取决于你想要什么,并取决于应用程序的要求。 VaD背后的想法是将内容和容器分开。 如果你实现了VaD你可以使用这个模板(默认),当你显示任何这种types的项目。 您可以在ItemsControls (列表,列表视图,网格等)中使用它,并在ContentControls仅使用绑定。 就像你说的那样, VaD作用是closures窗口的内容并打开一个新窗口。 你也可以使用UserControls来定义视图,然后控制是否有焦点的元素,也可以pipe理后面的代码。 所以,你的数据模板可能是这样的:

 <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设置依赖项属性,这使得工作更容易,因为允许绑定和解耦应用程序。

但是,当然,如果你的应用程序不需要dynamic的内容切换,那么在主窗口或其他窗口中使用VaW是很好的。 事实上,你可以同时使用VaWVaD 。 这最后一个可以用于应用程序中的内部项目,这不需要窗口。 您根据应用程序要求select了更适合您的应用程序,以及开发应用程序的时间。 希望这个个人的经验帮助…