Model-View-ViewModel(MVVM)模式可帮助开发人员从其用户界面分离应用程序的业务和表示逻辑。 在应用程序逻辑和用户界面之间保持清晰的分离有助于解决开发和设计问题,使应用程序更易于测试,维护和开发。 它还可以提高代码的可重用性,并允许多个开发人员在同一项目上工作时更轻松地协作。
1.简介
使用MVVM模式,应用程序的用户界面以及基础表示和业务逻辑被分为三个组件:
- 视图组件封装了用户界面和用户界面逻辑。
- 视图模型组件封装了表示逻辑和状态。
- 模型层封装了应用程序的业务逻辑和数据。
有多种框架可用于在Windows应用程序中实现MVVM模式。 哪种框架最适合您的项目取决于您的要求。 在本教程中,我们将使用MVVM Light ,这是一种流行且易于使用的MVVM框架。
本教程向您展示如何创建具有MVVM Light支持的Universal Windows应用程序。 你将学到如何:
- 创建一个通用Windows应用程序并添加对MVVM Light的支持
- 实现目录结构
- 添加视图模型层
- 连接数据上下文
- 实现Messenger服务在视图模型之间传递消息
2.项目设置
步骤1:建立通用Windows应用程式
首先创建一个通用Windows应用程序。 从Visual Studio的“ 文件”菜单中选择“ 新建项目 ”。 展开模板 > Visual C# > Windows > Windows 8 > 通用,然后从项目模板列表中选择空白应用程序(通用Windows 8.1) 。 为您的项目命名,然后单击“ 确定”以创建该项目。
![创建通用Windows应用](https://i-blog.csdnimg.cn/blog_migrate/d131cc3fbcf89413756bf08536d95546.png)
这将创建两个新应用(Windows Phone 8.1和Windows 8.1)和一个共享项目。 Windows Phone 8.1和Windows 8.1项目是特定于平台的项目,负责创建针对各个平台的应用程序包(.appx)。 共享项目是在两个平台上运行的代码的容器。
步骤2:添加MVVM Light支持
在解决方案资源 管理 器中右键单击解决方案名称,然后选择“ 管理解决方案的Nuget程序包” 。
![选择管理解决方案的Nuget软件包](https://i-blog.csdnimg.cn/blog_migrate/536854525d2e4ebb97ed099dcaf8837f.png)
选择浏览选项卡,然后搜索MVVM Light 。 从搜索结果中选择软件包MvvmLightLibs 。 检查Windows 8.1和Windows Phone 8.1项目,然后单击“ 安装”以将MVVM Light库添加到应用程序。
![搜索并安装MvvmLightLibs](https://i-blog.csdnimg.cn/blog_migrate/dff21f5813f94f7a4b5b90e8c0ecb1a8.png)
至此,您已经为两个应用程序添加了MVVM Light支持。
3.项目文件结构
采用MVVM模式的通用Windows应用程序需要特定的目录结构。 以下快照显示了通用Windows应用程序可能的项目文件结构。
![项目文件结构](https://i-blog.csdnimg.cn/blog_migrate/a8b9fc537f1d9256a1a81844656a1cf9.png)
让我向您介绍采用MVVM模式的典型Univesal Windows应用程序的项目结构:
- 控件 :此目录包含可重用的用户界面控件(与应用程序无关的视图)。 特定于平台的控件直接添加到特定于平台的项目中。
- 字符串 :此目录包含用于应用程序本地化的字符串和资源。 Strings目录包含每种受支持语言的单独目录。 例如, en-US目录包含英语(US)语言的资源。
- 模型 :在MVVM模式中,模型封装了业务逻辑和数据。 通常,该模型实现的功能使将属性绑定到视图层变得容易。 这意味着它通过
INotifyPropertyChanged
和INotifyCollectionChanged
接口支持“属性更改”和“集合更改”通知。 - ViewModels :MVVM模式中的视图模型封装了视图的表示逻辑和数据。 它没有直接引用视图或与视图的实现或类型有关的任何知识。
- 转换器 :此目录包含值转换器。 值转换器是一种将数据从一种类型转换为另一种类型的便捷方法。 它实现了
IValueConverter
接口。 - 主题 :“ 主题”目录包含类型为
ResourceDictionary
主题资源。 平台特定资源直接添加到特定项目,共享资源添加到共享项目。 - 服务 :此部分可以包括网络服务调用,导航服务等的类。
- utils的包括可以在整个应用使用效用函数。 示例包括
AppCache
,FileUtils
,Constants
,NetworkAvailability
,GeoLocation
等。 - 视图 :此目录包含用户界面布局。 特定于平台的视图直接添加到特定于平台的项目,而公共视图则添加到共享项目。
根据视图的类型,名称应以以下结尾:
- 窗口 ,非模式窗口
- 对话框 ,(模式)对话框窗口
- Page ,页面视图(主要用于Windows Phone和Windows Store应用程序)
- View ,在另一个视图,页面,窗口或对话框中用作子视图的视图
视图模型的名称由相应视图的名称和单词“ Model”组成。 视图模型与它们在Views目录中的对应视图存储在ViewModels目录中的相同位置。
4.添加视图模型层
视图模型层实现了属性和命令,视图可以将数据绑定到这些属性和命令,并通过更改通知事件将任何状态更改通知给视图。 视图模型提供的属性和命令定义了用户界面提供的功能。 以下列表总结了视图模型层的特征,任务和职责:
- 它协调视图与任何模型类的交互。
- 视图模型和模型类通常具有一对多关系。
- 它可以转换或操纵模型数据,以便视图可以轻松使用它。
- 它可以定义其他属性以专门支持该视图。
- 它定义了视图可用于向用户界面提供可视更改的逻辑状态。
- 它定义了用户可以触发的命令和动作。
在接下来的步骤中,我们将两个文件ViewModelLocator.cs和MainViewModel.cs添加到视图模型层。
步骤1:添加MainViewModel
类
首先,右键单击共享项目,然后选择添加 , 新建文件夹 。 将文件夹命名为ViewModels 。 接下来,右键单击ViewModels文件夹,然后选择Add , New Item以添加MainViewModel
类。
修改MainViewModel
类,如下所示:
public class MainViewModel : ViewModelBase
{
private string _helloWorld;
public string HelloWorld
{
get
{
return _helloWorld;
}
set
{
Set(() => HelloWorld, ref _helloWorld, value);
}
}
public MainViewModel()
{
HelloWorld = IsInDesignMode
? "Runs in design mode"
: "Runs in runtime mode";
}
}
该类包含一个string
类型的公共属性HelloWorld
。 您可以向视图模型添加其他方法,可观察的属性和命令。
步骤2:添加ViewModelLocator
类
我们将为ViewModelLocator
类中的所有视图模型添加一个公共属性,并创建一个新资源,该资源将在设计器中使用。
右键单击ViewModels文件夹,然后选择Add , New Item 。 选择一个类并将其命名为ViewModelLocator.cs 。 如下所示更新ViewModelLocator
类。
public class ViewModelLocator
{
public MainViewModel Main
{
get
{
return ServiceLocator.Current.GetInstance<MainViewModel>();
}
}
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<MainViewModel>();
}
}
ViewModelLocator
类包含一个公共属性Main
,该属性的getter返回MainViewModel
类的实例。 ViewModelLocator
的构造函数将MainViewModel
实例注册到SimpleIoc
服务。
接下来,打开App.xaml文件,并使用要在设计器中使用的ViewModelLocator
添加新资源。
<Application.Resources>
<viewModels:ViewModelLocator x:Key="Locator" />
</Application.Resources>
5.连接数据上下文
视图和视图模型可以在运行时以多种方式构造和关联。 对于视图,最简单的方法是在XAML中实例化其对应的视图模型。 您还可以在XAML中指定将视图模型设置为视图的数据上下文。
<Page.DataContext>
<vm:MainViewModel/>
</Page.DataContext>
初始化MainPage.xaml页面时,将自动构造MainViewModel
的实例并将其设置为视图的数据上下文。 请注意,视图模型必须具有默认的无参数构造函数,此方法才能起作用。
另一种方法是在视图的构造函数中以编程方式创建视图模型实例,并将其设置为数据上下文。
public MainPage()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
另一种方法是创建视图模型实例,并使用视图模型定位器将其与其视图关联。 在示例应用程序中,我们使用ViewModelLocator
类来解析MainPage.xaml的视图模型。
<Page.DataContext>
<Binding Path="Main" Source="{StaticResource Locator}" />
</Page.DataContext>
现在,视图的数据上下文已设置为MainViewModel
类,我们可以在视图中访问其属性。 您可以将TextBlock
的文本绑定到视图模型中定义的HelloWorld
属性。
<TextBlock Text="{Binding HelloWorld}" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center"/>
6.信使服务
MVVM Light中的Messenger服务允许在视图模型之间或视图模型与视图之间进行通信。 假设您有一个视图模型用于为搜索功能提供业务逻辑,并且页面上有两个视图模型要处理搜索以显示输出。 使者将是松散绑定的理想方式。
获取搜索数据的视图模型将仅发送“搜索”消息,该消息将被当前注册以使用该消息的任何视图模型所消耗。 使用Messenger服务的好处是:
- 视图模型之间的轻松通信,而无需每个视图模型都彼此了解
- 可以毫不费力地添加更多消息消费者
- 它使视图模型保持简单
发送消息:
MessengerInstance.Send(payload, token);
接收消息:
MessengerInstance.Register<PayloadType>(
this, token, payload => SomeAction(payload));
在示例应用程序中,我们将从MainViewModel
发送一条消息,该消息将被MainPage.xaml接收。 这些是使用Messenger服务所需的步骤。
步骤1:创建类以包含要传递的消息
在项目中创建一个新类,并将其命名为ShowMessageDialog
。
public class ShowMessageDialog
{
public string Message { get; set; }
}
步骤2:实例化消息类和广播消息
在MainViewModel.cs中 ,创建ShowMessageDialog
的实例,然后使用Messenger
对象广播消息。
private object ShowMessage()
{
var msg = new ShowMessageDialog { Message = "Hello World" };
Messenger.Default.Send<ShowMessageDialog>(msg);
return null;
}
这将广播消息。 我们要做的就是注册收件人并回复邮件。
步骤3:注册消息并在收到时进行处理
打开MainPage.xaml.cs并在构造函数中注册消息。
public MainPage()
{
this.InitializeComponent();
Messenger.Default.Register<ShowMessageDialog>
(
this,
(action) => ReceiveMessage(action)
);
}
ReceiveMessage
是您需要实现的方法。 它将使用Message
对象,并使用DialogService
来显示一个对话框。
private async void ReceiveMessage(ShowMessageDialog action)
{
DialogService dialogService= new DialogService();
await dialogService.ShowMessage(action.Message, "Sample Universal App");
}
步骤4:创建命令以发送消息
现在我们可以发送和接收消息了,我们需要调用ShowMessage
方法。 MVVM Light提供对RelayCommand
支持,该命令可用于在视图模型中创建命令。 在调用ShowMessage
方法的MainViewModel
类中添加一个公共属性ShowMessageCommand
。
private RelayCommand _showMessageCommand;
public RelayCommand ShowMessageCommand => _showMessageCommand ?? (_showMessageCommand = new RelayCommand(ShowMessage));
接下来,将一个Button
添加到MainPage.xaml ,并将ShowMessageCommand
绑定到其Command
属性。
<Button Command="{Binding ShowMessageCommand}" Content="Click Me" HorizontalAlignment="Center"/>
部署应用程序以查看一切是否按预期工作。 这是MainPage.xaml在Windows 8.1上的外观快照。
![MainPagexaml用户界面](https://i-blog.csdnimg.cn/blog_migrate/662e9d8df443c2747df6e111b25de921.png)
当您单击“ 单击我”按钮时,将弹出一个对话框。
![MainPagexaml上的对话框弹出](https://i-blog.csdnimg.cn/blog_migrate/a396289a4d416199ed738b1d63b2d038.png)
Messenger是一个功能强大的组件,可以使通信更轻松,但同时也使代码更难调试,因为乍一看它并不总是很清楚哪些对象正在接收消息。
结论
通过实现MVVM模式,我们可以在视图,视图模型和模型层之间实现清晰的分离。 通常,我们尝试开发视图模型,以使它对驱动的视图一无所知。 这具有多个优点:
随时下载本教程的源文件以用作参考。
翻译自: https://code.tutsplus.com/tutorials/how-to-use-mvvm-in-a-universal-windows-app--cms-25582