2010-01-01 107 views
14

我最近开始调查MVVM模式与WPF为即将到来的项目。我开始于Josh Smith's MSDN article.我有一个问题(很多,但让我们从一个开始):MVVM(与WPF) - 将多个视图绑定到相同的ViewModel

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

现在这种方法的工作,这些类是相当小,但我想知道是否有可能只有一个视图模型,这暴露了两个命令。我仍然会有2个视图绑定到这个相同的视图模型,并将适当的命令暴露为一个按钮。我不太清楚如何做到这一点。在主窗口中的资源我有类似:

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

随着结合你只能拥有这方法的一个一对一绑定,即同样的看法总是显示为一个给定的视图模型。有没有办法根据视图模型上的属性(例如IndividualViewModel.Mode)自动切换视图。我应该考虑一种不同的方法吗?

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

谢谢!

回答

1

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

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

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

4

感谢您指点我正确的方向!我也是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; 
    } 
} 

这可能是也可能不是如何实现最终的东西(给定的要求),但它是很好的看到我有这种可用的选项。

1

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

  1. 从IndividualVM派生EditIndividualVM和AddINdividualVM。
  2. Edit-和AddCommands路由到IndividualVM中的setter属性。
  3. 取决于哪个按钮被按下,setter VM =新的AddIndividualVM或VM =新的EditIndividualVM。
  4. 在XAML您在contentgrid绑定到你的虚拟机性能是这样的:

+2

看来你有缺少的代码。你可以用代码片段更新你的答案吗? – PlagueHammer 2013-12-19 22:30:54

4

所以,你需要根据属性值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> 
+0

这是经典的MVVM解决方案。 它指定了两个选项并且没有代码。 – 2017-12-06 09:52:22

相关问题