Подтвердить что ты не робот

WPF: переключение UserControls в зависимости от соответствующих ViewModels (MVVM)

Я попытаюсь упростить задачу, над которой я работаю, воображая этот пример:

Предположим, что мы имеем следующую иерархию модельных классов:

Animal
   Lion
   Snake
   Bird

... соответствующие ViewModels:

AnimalCollectionViewModel
   AnimalViewModel
      LionViewModel
      SnakeViewModel
      BirdViewModel

... и соответствующие представления:

AnimalCollectionView
   LionView
   SnakeView
   BirdView

Предполагалось, что AnimalCollection содержит список, заполненный объектами разных типов животных, и ниже списка он имеет сетку свойств для задания свойств выбранного животного. Очевидно, сетки свойств будут иметь разные свойства и должны измениться при изменении типа выбранного элемента.

Возникает вопрос: как реализовать коммутацию свойств в WPF в соответствии с шаблоном MVVM? С помощью какого механизма?

В настоящее время у меня есть абстрактное свойство enum в базовом ViewModel (AnimalViewModel.PropertyGridType = {Lion, Snake, Bird}), который производные классы реализуют, возвращая соответствующие значения. И AnimalCollectionView изменяет элементы управления сетью свойств в зависимости от значения этого свойства. Что-то вроде этого:

...

<UserControl.Resources>
    <Style x:Key="PropertyGridStyle" TargetType="ContentControl">
        <Style.Triggers>
            <DataTrigger Binding="{Binding PropertyGridType}" Value="Lion">
                <Setter Property="Content">
                    <Setter.Value>
                        <view:LionPropertyGridView />
                    </Setter.Value>
                </Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding PropertyGridType}" Value="Snake">
                <Setter Property="Content">
                    <Setter.Value>
                        <view:SnakePropertyGridView />
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

<ContentControl Style="{StaticResource PropertyGridStyle}" />

...

Но я не уверен, что это правильный подход. (По крайней мере, мне не нравится вводить вспомогательное свойство enum. Можно ли вывести необходимый пользовательский элемент управления на основе типа ViewModel?) Может ли кто-нибудь посоветовать другие варианты? Спасибо заранее!

4b9b3361

Ответ 1

Можно ли выводить необходимое пользовательское управление на основе типа ViewModel?

Вы имеете в виду, как это?

<Window.Resources>
   <DataTemplate DataType="{x:Type vm:LionViewModel}">
      <v:LionView />
   </DataTemplate>
   <DataTemplate DataType="{x:Type vm:SnakeViewModel}">
      <v:SnakeView />
   </DataTemplate>
   <DataTemplate DataType="{x:Type vm:BirdViewModel}">
      <v:BirdView"/>
   </DataTemplate>
</Window.Resources>

См. "Применение представления к модели представления" в статье статьи Джоша Смита о MVVM.

Edit:

Вот тривиальный пример выбора шаблона на основе типа, который вы можете вставить в Kaxaml, чтобы доказать себе, что он действительно работает:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <Page.Resources>
    <sys:String x:Key="string">this is a string</sys:String>
    <sys:Int32 x:Key="int32">1234</sys:Int32>
    <DataTemplate DataType="{x:Type sys:String}">
      <TextBlock Foreground="Red" Text="{Binding}"/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type sys:Int32}">
      <TextBlock Foreground="Blue" Text="{Binding}"/>
    </DataTemplate>
  </Page.Resources>
  <StackPanel>  
    <ContentControl Content="{Binding Source={StaticResource string}}"/>
    <ContentControl Content="{Binding Source={StaticResource int32}}"/>
  </StackPanel>
</Page>

Ответ 2

Вы можете использовать DataTemplateSelector. Способ выбора правильного шаблона зависит от вас. Вы можете использовать перечисления или проверить тип класса, если хотите.