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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19864891/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 16:02:09  来源:igfitidea点击:

WPF MVVM Why use ContentControl + DataTemplate Views rather than straight XAML Window Views?

c#wpfxamlmvvmarchitecture

提问by Simon F

Why This?

为什么这个?

MainWindow.xaml:

主窗口.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>

Have your ExampleView.xaml set up as:

将您的 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>

And create the window like this:

并像这样创建窗口:

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();
    }
}


When it can be done like this?

什么时候可以做到这样?

App.xaml: (Set startup window/View)

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: (a Window not a ResourceDictionary)

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>


Essentially it's "View as DataTemplate" (VaD) vs. "View as Window" (VaW)

本质上它是“作为数据模板查看”(VaD)与“作为窗口查看”(VaW)

Here is my understanding of the comparison:

以下是我对比较的理解:

  • VaD: Lets you switch Views without closing the window. (This is not desirable for my project)
  • VaD: VM knows absolutely nothing about the View, whereas in VaW it (only) has to be able to instantiate it when opening another window
  • VaW: I can actually see my xaml rendered in the Designer (I can't with VaD, at least in my current setup)
  • VaW: Works intuitively with opening and closing windows; each window has (is) a corresponding View (and ViewModel)
  • VaD: ViewModel can pass along initial window width, height, resizability etc. through properties (whereas in VaW they are directly set in the Window)
  • VaW: Can set FocusManager.FocusedElement (not sure how in VaD)
  • VaW: Less files, since my window types (e.g. Ribbon, Dialog) are incorporated into their Views
  • VaD:让您无需关闭窗口即可切换视图。(这对我的项目来说是不可取的)
  • VaD:VM 对 View 一无所知,而在 VaW 中,它(仅)必须能够在打开另一个窗口时实例化它
  • VaW:我实际上可以在设计器中看到我的 xaml(我不能使用 VaD,至少在我当前的设置中)
  • VaW:直观地打开和关闭窗口;每个窗口都有(是)一个对应的视图(和视图模型)
  • VaD:ViewModel 可以通过属性传递初始窗口宽度、高度、可调整大小等(而在 VaW 中它们直接在 Window 中设置)
  • VaW:可以设置 FocusManager.FocusedElement(不确定在 VaD 中如何)
  • VaW:更少的文件,因为我的窗口类型(例如功能区、对话框)被合并到它们的视图中


So what's going on here? Can't I just build my windows in XAML, access their data cleanly through properties of the VM, and be done with it? The code-behind is the same (virtually nil).

那么这里发生了什么?我不能只在 XAML 中构建我的窗口,通过 VM 的属性干净地访问它们的数据,然后完成它吗?代码隐藏是相同的(几乎为零)。

I'm struggling to understand why I should shuffle all the View stuff into a ResourceDictionary.

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

采纳答案by Federico Berasategui

People use DataTemplatesthat way when they want to dynamically switch Views depending on the ViewModel:

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

So,

所以,

if Window.DataContextis an instance of VM1, then View1will be displayed,

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

and if

而如果

Window.DataContextis an instance of VM2, then View2will be displayed.

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

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

当然,如果只需要 1 个视图并且从未更改,则完全没有意义。

回答by Raúl Ota?o

From my personal experience: Both work models are aviables, depending of what you want, and depending of the application requirements. The idea behind VaDis decopling the content, and the container. If you implement VaDyou 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 ContentControlsonly making bindings. Like you said, VaDworks 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:

根据我的个人经验:两种工作模式都是可行的,这取决于您想要什么,以及取决于应用程序要求。背后的想法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>

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

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

But of course, if you app doesn't require dynamically content switching, it is fine to use VaWfor the main window, or any other window. In fact, you can use both VaWand 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...

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

回答by Phillip Ngan

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.

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