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.DataContext
是VM1
一个实例,则将显示View1
,
而如果
Window.DataContext
是VM2
一个实例,那么将显示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
是很好的。 事实上,你可以同时使用VaW
和VaD
。 这最后一个可以用于应用程序中的内部项目,这不需要窗口。 您根据应用程序要求select了更适合您的应用程序,以及开发应用程序的时间。 希望这个个人的经验帮助…