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

Nic*_*olo 20 wpf mvvm

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

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

Animal
   Lion
   Snake
   Bird
Run Code Online (Sandbox Code Playgroud)

...对应的ViewModels:

AnimalCollectionViewModel
   AnimalViewModel
      LionViewModel
      SnakeViewModel
      BirdViewModel
Run Code Online (Sandbox Code Playgroud)

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

AnimalCollectionView
   LionView
   SnakeView
   BirdView
Run Code Online (Sandbox Code Playgroud)

假设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}" />
Run Code Online (Sandbox Code Playgroud)

...

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

Rob*_*ney 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>
Run Code Online (Sandbox Code Playgroud)

请参阅Josh Smith关于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>
Run Code Online (Sandbox Code Playgroud)

  • 我几乎可以肯定这正是我的意思:))谢谢你,罗伯特 (2认同)
  • 您可以在项控件或内容控件中使用它们.例如,`<ContentControl Content ="{Binding X}"/>`创建一个`ContentPresenter`,它包含与`X`类型匹配的任何数据模板,就像`<ItemsControl ItemsSource ="{Binding X}"/> `创建一个充满`ItemsPresenters`的面板.(通常,具有`ItemsSource`属性的任何东西都是一个项控件;任何带有`Content`属性的东西都是一个内容控件.) (2认同)