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个不同的
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> |
如果您认为这太过分了,则可以使用触发器并将特定的视图包装到
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。
在xaml中,您将contentgrid绑定到VM属性,如下所示:
没有理由为什么您不能实现该目标。一种方法是在视图模型中提供一些标志,说明您是处于添加模式还是处于编辑模式,并使用简单的绑定,触发器或模板选择器根据该标志来设计视图样式。
作为参考,您可以看一下Sacha Barber的
基本上,不是在视图模型中具有简单的属性,而是实例化包含