关于MVVM(带有WPF):MVVM(带有WPF)-将多个视图绑定到同一个ViewModel

MVVM (with WPF) - Binding Multiple Views to the Same ViewModel

我最近开始针对即将进行的项目使用WPF研究MVVM模式。我从Josh Smith的MSDN文章开始。我有一个问题(很多问题,但让我们开始一个问题):

我有一个个人视图模型,它公开了模型的属性。我需要两个视图"添加个人"和"编辑个人",这两个视图非常相似。我目前所做的是有2个子类AddIndividualViewModel和EditIndividualViewModel分别公开了Add和Edit命令。我也有2个相似的命名视图绑定到这些视图。

现在,此方法有效,并且这些类无论如何都是很小的,但是我想知道是否可以仅使用一个视图模型来公开这两个命令。我仍然会有2个视图绑定到相同的视图模型,将适当的命令显示为按钮。我不太确定该怎么做。在主窗口资源中,我有类似以下内容:

1
2
3
        <DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}">
            <Views:AddIndividualView />
        </DataTemplate>

使用这种绑定方法,您只能进行一对一的绑定,即对于给定的视图模型始终显示同一视图。有没有一种方法可以根据视图模型上的属性(例如,IndividualViewModel.Mode)自动切换视图。我应该考虑采用其他方法吗?

请注意,主窗口具有视图模型的集合,并在选项卡中显示每个视图模型。

谢谢!


感谢您指出正确的方向!我对WPF还是很陌生,并且了解所有不同的可能性,包括绑定方法。无论如何,对于任何有兴趣的人,这是我针对此特定情况得出的解决方案:

我决定将视图模型分为两个子类AddIndividualViewModel和EditIndividualViewModel分开,这两个子类仅公开命令,而不是试图在一个类中管理状态。但是,我想要一个视图,这样就不会复制XAML。我最终使用了两个DataTemplates和DataTemplateSelector来根据视图模型切换出动作按钮:

1
2
3
4
5
6
7
8
9
10
11
12
        <DataTemplate x:Key="addTemplate">
            <Button Command="{Binding Path=AddCommand}">Add</Button>
        </DataTemplate>

        <DataTemplate x:Key="editTemplate">
            <Button Command="{Binding Path=UpdateCommand}">Update</Button>
        </DataTemplate>

        <TemplateSelectors:AddEditTemplateSelector
            AddTemplate="{StaticResource addTemplate}"
            EditTemplate="{StaticResource editTemplate}"
            x:Key="addEditTemplateSelector" />

表单底部的内容演示者:

1
2
        <ContentPresenter Content="{Binding}"
                          ContentTemplateSelector="{StaticResource addEditTemplateSelector}" />

这是模板选择器的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class AddEditTemplateSelector : DataTemplateSelector
{
    public DataTemplate AddTemplate { get; set; }
    public DataTemplate EditTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item is AddIndividualViewModel)
        {
            return AddTemplate;
        }
        else if (item is EditIndividualViewModel)
        {
            return EditTemplate;
        }

        return null;
    }
}

这可能是(也可能不是)如何实现最终目标(根据需求),但是很高兴看到我有这种可用的选项。


因此,您需要基于属性值的2个不同视图。要考虑的一件事是重构您的表示代码,因此可以使用真正的子类来代替属性的值。然后,您可以为每个类使用2个不同的DataTemplate

1
2
3
4
5
6
7
<DataTemplate DataType="{x:Type ViewModels:AddIndividualViewModel}">
  <Views:AddIndividualView />
</DataTemplate>

<DataTemplate DataType="{x:Type ViewModels:EditIndividualViewModel}">
  <Views:EditIndividualView />
</DataTemplate>

如果您认为这太过分了,则可以使用触发器并将特定的视图包装到ContentPresenter中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<DataTemplate x:Key="AddIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}">
  <Views:AddIndividualView />
</DataTemplate>

<DataTemplate x:Key="EditIndividualTemplate" DataType="{x:Type ViewModels:IndividualViewModel}">
  <Views:EditIndividualView />
</DataTemplate>

<DataTemplate DataType="{x:Type ViewModels:IndividualViewModel}">
  <ContentPresenter Content="{Binding}">
    <ContentPresenter.Style>
      <Style TargetType="ContentPresenter">
        <Setter Property="ContentTemplate" Value="{StaticResource AddIndividualTemplate}" />
        <Style.Triggers>
          <DataTrigger Binding="{Binding Mode}" Value="{x:Static ViewModels:IndividualMode.Edit}">
            <Setter Property="ContentTemplate" Value="{StaticResource EditIndividualTemplate}" />
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </ContentPresenter.Style>
  </ContentPresenter>
</DataTemplate>


对于此任务,您根本不需要任何DataTemplateSelector。

  • 从IndividualVM派生EditIndividualVM和AddINdividualVM。
  • Edit-和AddCommands路由到IndividualVM中的setter属性。
  • 设置器VM =新的AddIndividualVM或VM =新的EditIndividualVM,具体取决于按下哪个按钮。
  • 在xaml中,您将contentgrid绑定到VM属性,如下所示:


  • 没有理由为什么您不能实现该目标。一种方法是在视图模型中提供一些标志,说明您是处于添加模式还是处于编辑模式,并使用简单的绑定,触发器或模板选择器根据该标志来设计视图样式。

    作为参考,您可以看一下Sacha Barber的DataWrapper类,该类是他的Cinch框架的一部分(不适用于您的情况,但这是一个很好的起点),该类将数据字段包装在视图模型中以支持标记可在只读(查看记录模式)和读写(编辑记录模式)之间切换。您可以应用类似的方法来区分添加和编辑。

    基本上,不是在视图模型中具有简单的属性,而是实例化包含Value属性和IsAdding属性的数据包装器类。在您的视图中,可以使用绑定,触发器或模板选择器基于该属性来修改模板。