【问题标题】:MVVM (with WPF) - Binding Multiple Views to the Same ViewModelMVVM (with WPF) - 将多个视图绑定到同一个 ViewModel
【发布时间】:2010-12-31 14:46:38
【问题描述】:

我最近开始为即将到来的项目研究带有 WPF 的 MVVM 模式。我从Josh Smith's MSDN article. 开始我有一个问题(很多,但让我们从一个开始):

我有一个 IndividualViewModel 公开模型的属性。我需要两个视图“添加个人”和“编辑个人”,您可以想象它们非常相似。我目前所做的是有 2 个子类 AddIndividualViewModel 和 EditIndividualViewModel 分别公开 Add 和 Edit 命令。我还有 2 个类似命名的视图绑定到这些视图。

现在这个方法有效,而且这些类还是相当小,但我想知道我是否有可能只有一个视图模型,它公开了两个命令。我仍然会有 2 个视图绑定到同一个视图模型,将适当的命令作为按钮公开。我不太确定该怎么做。在主窗口资源中,我有类似的内容:

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

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

请注意,主窗口有一组视图模型,并在选项卡中显示每个模型。

谢谢!

【问题讨论】:

    标签: wpf mvvm binding viewmodel


    【解决方案1】:

    因此,您需要基于属性值的 2 个不同视图。要考虑的一件事是refactor your presentation code,因此您可以拥有真正的子类,而不是属性的值。然后你可以为每个类使用 2 个不同的DataTemplate

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

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

    <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>
    

    【讨论】:

    • 这是经典的 MVVM 解决方案。它指定了这两个选项,并且没有后面的代码。
    【解决方案2】:

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

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

            <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" />
    

    和表单底部的内容演示者:

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

    这是模板选择器的代码:

    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;
        }
    }
    

    这可能是也可能不是最终实现的方式(鉴于要求),但很高兴看到我有这种可用的选项。

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

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

        1. 从 IndividualVM 派生 EditIndividualVM 和 AddINdividualVM。
        2. Edit- 和 AddCommands 路由到 IndividualVM 中的 setter 属性。
        3. setter VM = new AddIndividualVM 或 VM = new EditIndividualVM,具体取决于按下的按钮。
        4. 在 xaml 中,您将 contentgrid 绑定到您的 VM 属性,如下所示:

        【讨论】:

        • 您的代码似乎丢失了。你能用代码 sn-p 更新你的答案吗?
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-06-04
        • 2017-11-08
        • 1970-01-01
        • 2013-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多