我们在开发爱奇艺UWP客户端的过程中广泛的使用了MVVM模式,下面简单的介绍一下MVVM模式。
MVVM模式定义
MVVM包括三个核心模块:Model,View,View-Model
Model
-
Model是要处理的实际数据。
-
但不包括处理这些数据的操作或服务。
-
也不是用来把数据转换成某种格式来方便UI显示的。数据转换可以在ViewModel中处理,也可以定义Converter对数据进行转换。
-
业务逻辑通常独立于Model,封装成其他类来操作Model。
-
Model是易于复用的,Model可以在多个ViewModel中使用。
-
要保持Model的干净是具有挑战的。
例如:
-
业务逻辑对象,如User。
-
数据交换对象。
-
CLR元子对象,int, long, string。
-
自动产生的实体或代理对象,例如与数据库表对应的实体类,用来解析JSON或XML等数据的实体类。
View-Model
-
View和Model的中间层,通常称为View’s Model
-
给View提供ICommand属性。
-
提供其他属性管理View的状态,如Button是否可见(Visibility)状态。
-
调用其他服务获取或操作Model。
-
聚合一个或多个Model,通过Property的方式提供给View使用。
-
实现INotifyPropertyChanged,以满足UI绑定更新的需要。
-
对于集合,使用ObservableCollection等
View
- 包含主题,样式,UI布局,控件,数据绑定,事件,已经其他与用户之间的交互。
- 避免过多的逻辑代码,这些代码尽量放入ViewModel
- 通常View是用XAML来定义,有时可以使用少量代码。
- 通过数据绑定或者方法调用从View Model中获取数据。
- UI控件上的Command属性可以绑定到View Model的ICommand属性上。
- 可以通过绑定到ViewModel的属性上对UI控件的状态进行控制。
View和View-Model的关系
- View和View Model通过数据绑定,方法调用,属性,事件等进行关联。
- View Model导出Model给View,也需要定义View需要的其他状态信息,如IsAllowLogin。
- View需要管理UI Events。
- ViewModel中的Model和属性通过双向绑定进行数据更新。
ViewModel和Model的关系
- View Model导出Model,或者通过属性提供给View进行绑定。
- View Model包括服务接口,配置数据接口等,以便获取View所需要的数据。
MVVM的好处
- 开发和设计可以分开独立工作,设计师可以通过模拟数据对UI进行调试。
- View Model和Model可以对立于View的代码进行单元测试。
- 可以重新设计UI并重用View Model和Model的代码。
- View Model做为View和Model之间的适配器,可以避免View的变更而需要对Model做出修改。
MVVM的性能问题
- 避免过多的中间过渡数据,这些数据会导致过多的GC,从而影响性能。
- 数据绑定问题,数据绑定会需要额外的动态内存分配,导致UI性能降低。使用{x:Bind}来替代Binding改善UI性能。
- 通常把Button.Click绑定到View Model的Icommand属性上,这样会造成额外的开销。建议在后台代码使用Click Event,在事件中调用View Model的方法。
- UI中经常把一些不展示给用户的部分的Visibility属性绑定到View Model的属性上来控制这部分UI的可见性。推荐使用x:Load或者x:DeferLoadStrategy来延迟这部分UI的加载。
Sample
下面写一个简单例子:
- Model
public class LoginModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
private string userName = "Tester";
public string UserName
{
get {
return userName; }
set
{
userName = value;
OnPropertyChanged(nameof(UserName));
}
}
private string password = string.Empty;
public string Passowrd
{
get {
return password; }
set
{
password = value;
OnPropertyChanged(nameof(Passowrd));
}
}
}
-