假设我正在为汽车构建导航系统:
我过去这样安排的策略是让我的视图模型遵循与视图完全相同的层次结构。所以:
将视图绑定到视图模型的XAML将如下所示:
<Window.Resources>
<DataTemplate DataType="{x:Type vm:AudioViewModel}">
<view:AudioPanel />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ClimateViewModel}">
<view:ClimatePanel />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:NavigationViewModel}">
<view:NavigationPanel />
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentViewModel}" />
如果用户正在收听广播并决定将目的地输入导航系统,他们将点击导航模式按钮。 MainWindowViewModel上会有一个命令,它将系统模式更改为“Navigation”,并将CurrentViewModel设置为NavigationViewModel。这将导致NavigationView被交换。非常干净的解决方案。
不幸的是,虽然这样做的方式在执行模式下运行良好,但在尝试使用Expression Blend中的从属视图(比如AudioPanel)时会崩溃,因为父视图模型(MainWindowViewModel)不存在以提供AudioViewModel
MVVM Light和Simple MVVM等工具包中似乎支持的解决方案是使用ViewModelLocator,然后让视图通过绑定到定位器上的正确属性来设置它自己的DataContext。然后定位器提供视图模型的实例。
“ViewModelLocator处理方式”解决了“可设计性”问题,但我不清楚如何表示层次关系并处理一个视图到另一个视图的交换。从概念上讲,让视图模型保持子视图模型对我来说更有意义。它正确地表示了视图的层次结构,视图交换是一个快照,如果不再需要视图,关联的视图模型及其所有下属将通过删除对父项的引用来进行垃圾收集。
问题
构建ViewModelLocator以处理分层视图,根据系统模式交换视图和删除视图的最佳实践是什么?
具体做法是:
答案 0 :(得分:1)
看起来视图层次结构中的当前视图是视图“状态”的一部分,因此它将拥有自己的“模型”(viewmodel)实体来管理这种关系。我不会使用IoC容器,但我会用它来注册'视图管理器'用来创建'子视图'的工厂。
答案 1 :(得分:1)
事实证明,Visual Studio / Blend中有一个XAML设计属性,允许您设置元素的设计时DataContext
。这仅适用于设计时,因此应该可以继续使用数据模板连接DataContext
(即根本不需要ViewModelLocator或ViewManager)。
例如,假设您有一个名为AudioPanel
的视图和一个名为AudioViewModel
的视图模型。
您只需要在AudioViewModel
...
public class AudioViewModel : ViewModelBase
{
public int Volume { get; set; }
public AudioMode Mode { get; set; }
public ViewModelBase ModePanelViewModel { get; set; }
public AudioViewModel()
{
if (IsInDesignMode)
{
Volume = 5;
Mode = AudioMode.Radio;
ModePanelViewModel = new RadioViewModel();
}
}
}
...然后在您看来,您只需要声明d:DataContext
属性...
<UserControl x:Class="NavSystem.Views.AudioPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:NavSystem.ViewModels"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance vm:AudioViewModel, IsDesignTimeCreatable=True}">
只要为在设计时发挥作用的每个视图模型编写默认构造函数,就应该可以在VS或Blend设计器中查看复合用户界面。
有关详细信息,请参阅此博文: http://karlshifflett.wordpress.com/2009/10/28/ddesigninstance-ddesigndata-in-visual-studio-2010-beta2/