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?)
Может ли кто-нибудь посоветовать другие варианты?
Спасибо заранее!
Ответы
Ответ 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. Способ выбора правильного шаблона зависит от вас. Вы можете использовать перечисления или проверить тип класса, если хотите.