MVVM模式学习(一)
MVVM是Model-View-ViewModel(模型-视图-视图模型)的简写,本质上是MVC的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点
- 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
- 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
- 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。
下面是一个简单在WPF项目中应用MVVM框架的示例:
1、首先根据Model-View-ViewModel框架名称在项目中分别建立Models、Views、ViewModels三个文件夹,代表Model、View、ViewModel三层架构,三层架构概念与功能:
Model层:核心数据层,存放各种核心数据类,该层不涉及逻辑,只是单纯定义各类数据及相应数据属性
ViewModel层:用我自己的理解来说,这一层是对Model层中的各类核心数据根据实际需求再次进行建模的过程,并且包含对数据进行操作的控制逻辑,建立好的模型同时拥有与界面层交互的能力
View层:顾名思义就是数据展示层,将数据以各种各样的表现形式在界面上显示出来
2、然后以建立多人信息表格为例,核心数据模型即是个人信息,在Model中建立Person类,包含姓名、年龄两个属性
public class Person
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
}
3、再在ViewModel中创建MainViewModel类(主视图模型),前文提到过ViewModel层具有与界面层交互的能力,反映在代码中即是该视图模型中用来展示的数据在发生改变的时候具有能够通知界面层改变的能力,这需要MainViewModel类实现InotifyPropertyChanged接口,由于ViewModel层可能不止有一个ViewModel,所以我们可以先建立一个已经实现了InotifyPropertyChanged接口的ViewModel的基类,然后让各ViewModel均继承这个基类即可,我这里将该基类定义为NoificationObject
public class NotificationObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
}
}
}
其中RaisePropertyChanged()方法便能够根据参数属性名通知界面哪个参数发生了改变
下面建立MainViewModel类(继承上面的基类)
展示层所关心的数据是多人的信息,那么ViewModel层中便需要有一个存储多个Person实例信息的集合成员Human,同时该成员改变时需通知界面层,MainViewModel类如下(可在Constructor中预先向Human中先填充一些数据):
public class MainViewModel:NotificationObject
{
private ObservableCollection<Person> human = null;
public ObservableCollection<Person> Human
{
get
{
return human;
}
set
{
human = value;
if (human != value)
{
human = value;
RaisePropertyChanged("Human");
}
}
}
public MainViewModel()
{
human = new ObservableCollection<Person>();
Human.Add(new Person { Name = "Tom", Age = 21 });
Human.Add(new Person { Name = "Jack", Age = 22 });
Human.Add(new Person { Name = "Rose", Age = 23 });
}
}
4、MainViewModel建立后,开始View展示层编写,由于这里只有一个界面,所以就在主界面中展示,Xaml代码如下
<Window.DataContext>
<ViewModel:MainViewModel></ViewModel:MainViewModel>
</Window.DataContext>
<StackPanel>
<DataGrid AutoGenerateColumns="False" Height="200" ItemsSource="{Binding Human}" HorizontalAlignment="Left" Margin="34,20,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="516">
<DataGrid.Columns>
<DataGridTextColumn Header="姓名" Binding="{Binding Name}"></DataGridTextColumn>
<DataGridTextColumn Header="年龄" Binding="{Binding Age}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
可以看出xaml代码中是通过wpf独有的DataContext和Binding等方法将ViewModel中的数据与界面关联起来
最后效果如下:
可以看出在主界面没有添加任何后台代码情况下便将数据显示出来,这是MVVM的优势,大大降低前端界面与后台代码的耦合性
还可以通过在MainViewModel中定义用于数据操作(逻辑控制)的Command,同样通过Binding的方式给添加按钮绑定Comand,从而实现界面对数据的操作
另外还有一个对MVVM框架进行进一步模块化和封装的框架——Prism框架,其中有类似定义好的模型视图基类或DelegateCommand等可让我们直接调用,大大方便了基于MVVM框架的开发