WPF:根据相应的ViewModels(MVVM)切换UserControls

时间:2011-02-16 15:51:02

标签: wpf mvvm

我会试着通过想象这个例子来简化我正在进行的任务:

假设我们有以下模型类层次结构:

Animal
   Lion
   Snake
   Bird

...对应的ViewModels:

AnimalCollectionViewModel
   AnimalViewModel
      LionViewModel
      SnakeViewModel
      BirdViewModel

......和相应的观点:

AnimalCollectionView
   LionView
   SnakeView
   BirdView

假设AnimalCollection包含一个填充了不同类型动物对象的列表,并且在列表下方有一个属性网格,用于设置所选动物的属性。显然,属性网格将具有不同的属性,并且应在所选项目的类型更改时更改。

问题是:如何根据MVVM模式实现WPF中属性网格的切换?使用什么机制?

目前,我在基础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}" />

...

但我不确定这是否是正确的做法。 (至少我不喜欢引入辅助枚举属性。是否可以根据ViewModel类型推断出必要的用户控件?) 任何人都可以建议其他选择吗? 提前谢谢!

2 个答案:

答案 0 :(得分:22)

  

是否可以根据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>

请参阅Josh Smith's article on MVVM中的“将视图应用于视图模型”。

修改

以下是基于类型的模板选择的一个简单示例,您可以将其粘贴到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>

答案 1 :(得分:2)

您可以使用DataTemplateSelector。选择正确模板的方法取决于您。如果您愿意,可以使用枚举或测试类类型。