WPF MVVM Зачем использовать представления ContentControl + DataTemplate, а не прямые представления окон XAML?

83

Почему это?

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>

И создайте такое окно:

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

Вот мое понимание сравнения:

  • VaD: позволяет переключать просмотры, не закрывая окно. (Это нежелательно для моего проекта)
  • VaD: VM абсолютно ничего не знает о View, тогда как в VaW он (только) должен иметь возможность создавать его при открытии другого окна.
  • VaW: я действительно могу видеть свой xaml, отображаемый в конструкторе (я не могу с VaD, по крайней мере, в моей текущей настройке)
  • VaW: Интуитивно работает с открытием и закрытием окон; каждое окно имеет (есть) соответствующий View (и ViewModel)
  • VaD: ViewModel может передавать исходную ширину окна, высоту, возможность изменения размера и т. Д. Через свойства (тогда как в VaW они устанавливаются непосредственно в окне)
  • VaW: можно установить FocusManager.FocusedElement (не уверен, как в VaD)
  • VaW: меньше файлов, так как мои типы окон (например, лента, диалог) включены в их представления.

Так что здесь происходит? Разве я не могу просто создать свои окна в XAML, получить чистый доступ к их данным через свойства виртуальной машины и покончить с этим? Код программной части такой же (практически ноль).

Я изо всех сил пытаюсь понять, почему я должен перетасовать все материалы View в ResourceDictionary.

Саймон Ф
источник
2
Подумайте так: ViewModels должны отображаться либо в Windows, либо в UserControls. Poco должны отображаться в шаблонах данных. :)
dev hedgehog

Ответы:

130

Люди используют 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>

Так,

если Window.DataContextявляется экземпляром VM1, то View1будет отображаться,

и если

Window.DataContextявляется экземпляром VM2, то View2будет отображаться.

Конечно, это не имеет никакого смысла, если ожидается только 1 просмотр и никогда не менялся.

Федерико Берасатеги
источник
8

Поскольку в VaD модели представлений ничего не знают о представлениях, вы можете создать полностью функционирующее приложение, целиком состоящее только из моделей представлений и без представлений. Это приводит к возможности написания приложения, которое может полностью управляться кодом. Это, в свою очередь, дает возможность проводить интеграционное тестирование без графического интерфейса. Интеграционное тестирование через графический интерфейс, как известно, хрупкое, в то время как тестирование через модели представления должно быть более надежным.

Филип Нган
источник
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>

Вы также UserControlможете установить свойства зависимостей, что упростит работу, поскольку позволяет привязать и разъединять приложение.

Но, конечно, если ваше приложение не требует динамического переключения содержимого, его можно использовать VaWдля главного окна или любого другого окна. Фактически, вы можете использовать оба VaWи VaD. Последний можно использовать для внутренних элементов приложения, для которых не нужны окна. Вы выбираете, что лучше для вас, в зависимости от требований приложения и времени, необходимого для разработки приложения. Надеюсь, этот личный опыт поможет ...

Рауль Отаньо
источник