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

Sim*_*n F 75 c# architecture wpf xaml mvvm

我有一个关于WPF MVVM的问题,这让我感到沮丧.

为什么这样做:?

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>
Run Code Online (Sandbox Code Playgroud)

将您的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>
Run Code Online (Sandbox Code Playgroud)

并创建如下窗口:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

什么时候可以这样做:?

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>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

基本上它是"视图为DataTemplate"(VaD)与"视图为窗口"(VaW)

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

  • VaD:允许您在不关闭窗口的情况下切换视图.(这对我的项目来说不可取)
  • VaD:VM对View一无所知,而在VaW中它(仅)在打开另一个窗口时必须能够实例化它
  • VaW:我实际上可以在Designer中看到我的xaml呈现(我不能使用VaD,至少在我当前的设置中)
  • VaW:直观地打开和关闭窗户; 每个窗口都有(是)相应的View(和ViewModel)
  • VaD:ViewModel可以通过属性传递初始窗口宽度,高度,可调整性等(而在VaW中它们直接在Window中设置)
  • VaW:可以设置FocusManager.FocusedElement(不确定如何在VaD中)
  • VaW:文件较少,因为我的窗口类型(例如Ribbon,Dialog)被合并到他们的视图中

那么这里发生了什么?我不能只在XAML中构建我的窗口,通过VM的属性干净地访问它们的数据,并完成它吗?代码隐藏是相同的(几乎为零).我很难理解为什么我应该将所有View内容混合到ResourceDictionary中.(但我不想做错 ;-))


它甚至重要吗?有没有我错过的东西?非常感谢阅读.:o


感谢Rachel Lim和Nick Polyak对我对MVVM的了解

编辑:轻微的流量变化

Fed*_*gui 122

人们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>
Run Code Online (Sandbox Code Playgroud)

所以,

if Window.DataContext是一个实例VM1,然后View1会显示,

而如果

Window.DataContext是一个实例VM2,然后View2将显示.

当然,如果只有1个View是预期的,并且永远不会改变,那就毫无意义了.

我希望这很清楚:P


Phi*_*gan 8

因为在VaD中,视图模型对视图一无所知,所以您可以构建一个完全功能的应用程序,它完全由视图模型组成,没有视图.这导致编写可完全由代码驱动的应用程序的可能性.这反过来导致在没有GUI的情况下执行集成测试的可能性.通过GUI进行集成测试是非常脆弱的 - 而通过视图模型进行测试应该更加健壮.


Raú*_*año 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>
Run Code Online (Sandbox Code Playgroud)

您还UserControl可以设置依赖项属性,这样可以使作业更容易,因为允许绑定和解耦应用程序.

但是,当然,如果您的应用程序不需要动态内容切换,则可以VaW用于主窗口或任何其他窗口.事实上,你可以使用VaWVaD.最后一个可以用于应用程序中的内部项目,不需要窗口.根据应用程序要求和开发应用程序的时间,您可以找到更适合您的方法.希望这种个人经历有助于......