MVVMLight 使用两个视图






4.61/5 (25投票s)
如何在同一个窗口中使用带有多个视图的 MVVM Light 创建 MVVM 应用程序
在之前的文章中,我快速展示了如何使用 MVVM Light 创建单视图、单窗口 WPF 应用程序。 WPF 应用程序的趋势是拥有一个包含多个视图的单个窗口,以便减少弹出对话框或子窗口。 本文展示了如何使用 MVVM 和 WPF 构建一个简单的双视图应用程序。
入门
- 需要 VS2010
- 确保您已安装 Nuget
- 管理 Nuget 包引用并添加 MVVM Light
- 本文的示例代码位于 github
请注意,为了简洁起见,XAML 被省略了,您应该访问 git 存储库以获取原始代码。
托管多个视图
应用程序结构与之前的文章类似:我们有一个 MainWindow
、一个 ViewModelLocator
和一个 MainViewModel
。
一图胜千言,所以闲话少说,这是 VS2010 中项目结构的样子
该项目以典型的 MVVM 风格布局:3 个文件夹分别用于 Models
、ViewModels
和 Views
。 在这种情况下,我们没有任何 Models
,因此可以忽略它们。
从 Views
开始:我们只有两个 UserControl
XAML 文件,其中包含我们要呈现的视图。 第一个视图是上一篇文章中的视图。 第二个只是一个文本标签。
为两个不同的视图模型呈现两个不同视图的所有工作都发生在 *MainViewModel.cs*、*MainWindow.xaml* 和 *App.xaml* 中。
查看 MainWindow
XAML,我们看到以下内容;
<Window x:Class="TwoViews.MainWindow"
DataContext="{Binding Main,
Source={StaticResource Locator}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Content="{Binding CurrentViewModel}" />
<DockPanel Grid.Row="1" >
<Button Command="{Binding SecondViewCommand}"
Content="Second View"
DockPanel.Dock="Right" />
<Button Command="{Binding FirstViewCommand}"
Content="First View"
DockPanel.Dock="Left" />
</DockPanel>
</Grid>
</Window>
和以前一样,我们使用 ViewModelLocator
将我们的 Main
视图模型绑定到 MainWindow
。 但是,这次我们有一个 ContentControl
,它绑定到一个名为 CurrentViewModel
的新属性,以及两个绑定到切换 *视图模型* 的命令的按钮。 即使按钮被标记为切换视图,但实际上更新的是视图模型。
使其工作的下一步是实现一个 DataTemplate
,*每个视图模型*,它呈现与 ViewModel
关联的 View
。 我们在 *App.xaml* 中执行此操作(尽管我们可以在我们选择的任何 Resource
部分中执行此操作)
<Application x:Class="TwoViews.App"
xmlns:views="clr-namespace:TwoViews.Views"
xmlns:vm="clr-namespace:TwoViews.ViewModels"
StartupUri="MainWindow.xaml"
>
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" />
<DataTemplate DataType="{x:Type vm:SecondViewModel}">
<views:SecondView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:FirstViewModel}">
<views:FirstView />
</DataTemplate>
</Application.Resources>
</Application>
例如,这实际上说“如果我的数据类型是 FirstViewModel
,那么 WPF 框架应该呈现 FirstView
UserControl
。
因此,当我们的 ContentControl
的 Content
属性设置为 FirstViewModel
类型的对象时,*框架会为我们呈现正确的 View
*。
还应注意的是,由于 Content
属性已设置为特定的 ViewModel
,例如 FirstViewModel
,因此它也被设置为呈现的视图的 DataContext
,即 FirstView
,因此 FirstView
和 FirstViewModel
之间的数据绑定有效。
将所有这些连接在一起的应用程序的最后一部分是 MainViewModel
类。 显然,我们只需要每个视图模型的单个实例,因此我们只需声明每个视图模型的 static
实例
public class MainViewModel : ViewModelBase
{
private ViewModelBase _currentViewModel;
readonly static FirstViewModel _firstViewModel = new FirstViewModel();
readonly static SecondViewModel _secondViewModel = new SecondViewModel();
public ViewModelBase CurrentViewModel
{
get
{
return _currentViewModel;
}
set
{
if (_currentViewModel == value)
return;
_currentViewModel = value;
RaisePropertyChanged("CurrentViewModel");
}
}
public ICommand FirstViewCommand { get; private set; }
public ICommand SecondViewCommand { get; private set; }
public MainViewModel()
{
CurrentViewModel = MainViewModel._firstViewModel;
FirstViewCommand = new RelayCommand(() => ExecuteFirstViewCommand());
SecondViewCommand = new RelayCommand(() => ExecuteSecondViewCommand());
}
private void ExecuteFirstViewCommand()
{
CurrentViewModel = MainViewModel._firstViewModel;
}
private void ExecuteSecondViewCommand()
{
CurrentViewModel = MainViewModel._secondViewModel;
}
}
请注意,在 CurrentViewModel
属性中,我们还必须通过 ViewModelBase
定义的 INPC 接口 RaisePropertyChanged
。 这是为了使数据绑定在 WPF 中工作,即,当我们单击按钮时,视图会发生变化:如果省略此行,您将无法通过单击按钮来更改视图。
如果我们运行代码,我们现在可以看到我们可以在两个视图之间切换,并且两个视图都保持它们的状态(因为我们使用的是每个视图的 static
实例)
完成
您可能会觉得上面的代码看起来很重复:它的确是。 许多(如果不是全部)MVVM 框架都提供了“运行时辅助”来自动化此类事情。 通过这种方式,我的意思是,通过按照约定命名您的类,例如始终使用“View
”和“ViewModel
”后缀,MVVM 框架大量使用反射,并且可以在运行时关联您的视图和视图模型。 事实上,即使是上面的 MainViewModel
也经常被概括为 MVVM 框架提供的东西。
脚注
之前的文章/延伸阅读
示例代码位于 github。