65.9K
CodeProject 正在变化。 阅读更多。
Home

MVVMLight 使用两个视图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.61/5 (25投票s)

2012 年 2 月 1 日

CPOL

3分钟阅读

viewsIcon

170393

downloadIcon

8351

如何在同一个窗口中使用带有多个视图的 MVVM Light 创建 MVVM 应用程序

KB/Blogs/323187/mvvmlight_view1.png

之前的文章中,我快速展示了如何使用 MVVM Light 创建单视图、单窗口 WPF 应用程序。 WPF 应用程序的趋势是拥有一个包含多个视图的单个窗口,以便减少弹出对话框或子窗口。 本文展示了如何使用 MVVM 和 WPF 构建一个简单的双视图应用程序。

入门

  • 需要 VS2010
  • 确保您已安装 Nuget
  • 管理 Nuget 包引用并添加 MVVM Light
  • 本文的示例代码位于 github

请注意,为了简洁起见,XAML 被省略了,您应该访问 git 存储库以获取原始代码。

托管多个视图

应用程序结构与之前的文章类似:我们有一个 MainWindow、一个 ViewModelLocator 和一个 MainViewModel

一图胜千言,所以闲话少说,这是 VS2010 中项目结构的样子

KB/Blogs/323187/mvvmlight_vs.png

该项目以典型的 MVVM 风格布局:3 个文件夹分别用于 ModelsViewModelsViews。 在这种情况下,我们没有任何 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

因此,当我们的 ContentControlContent 属性设置为 FirstViewModel 类型的对象时,*框架会为我们呈现正确的 View*。

还应注意的是,由于 Content 属性已设置为特定的 ViewModel,例如 FirstViewModel,因此它也被设置为呈现的视图的 DataContext,即 FirstView,因此 FirstViewFirstViewModel 之间的数据绑定有效。

将所有这些连接在一起的应用程序的最后一部分是 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 实例)

KB/Blogs/323187/mvvmlight_view1.png

KB/Blogs/323187/mvvmlight_view2.png

完成

您可能会觉得上面的代码看起来很重复:它的确是。 许多(如果不是全部)MVVM 框架都提供了“运行时辅助”来自动化此类事情。 通过这种方式,我的意思是,通过按照约定命名您的类,例如始终使用“View”和“ViewModel”后缀,MVVM 框架大量使用反射,并且可以在运行时关联您的视图和视图模型。 事实上,即使是上面的 MainViewModel 也经常被概括为 MVVM 框架提供的东西。

脚注

之前的文章/延伸阅读

示例代码位于 github

© . All rights reserved.