WPF快速入门系列(8)——MVVM快速入门
最后更新于:2022-04-02 00:13:04
# WPF快速入门系列(8)——MVVM快速入门
## 一、引言
在前面介绍了WPF一些核心的内容,其中包括WPF布局、依赖属性、路由事件、绑定、命令、资源样式和模板。然而,在WPF还衍生出了一种很好的编程框架,即WVVM,在Web端开发有MVC,在WPF客户端开发中有MVVM,其中VM就相当于MVC中C(Control)。在Web端,微软开发了Asp.net MVC这样的MVC框架,同样在WPF领域,微软也开发了Prism这样的MVVM框架。Prism项目地址是:[http://compositewpf.codeplex.com/SourceControl/latest](http://compositewpf.codeplex.com/SourceControl/latest)。大家有兴趣的可以下载源码研究下。
## 本文所有源码下载:[FristMVVMProject.zip](http://files.cnblogs.com/zhili/FristMVVMProject.zip)
## 二、MVVM模式是什么?
既然讲到MVVM模式,自然第一个问题就是MVVM的含义。MVVM是Model-View-ViewModel的缩写形式,它通常被用于WPF或Silverlight开发。这三者之间的关系如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-23_56a2eb442341c.png)
下面我们分别来介绍下这三部分。
**模型(Model)**
Model——可以理解为带有字段,属性的类。
视图(View)
View——可以理解为我们所看到的UI。
视图模型(View Model)
View Model在View和Model之间,起到连接的作用,并且使得View和Model层分离。View Model不仅仅是Model的包装,它还包含了程序逻辑,以及Model扩展,例如,如果Model中有一个公开属性不需要在UI上显示,此时我们可以不再View Model中去定义它。
在MVVM模式下,WPF程序的运行流程如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-23_56a2eb4432336.png)
在MVVM中,VM的地位可以说是举足轻重。使用MVVM模式具有以下几个特点:
* 视图的cs文件包括极少的代码,其核心逻辑都被放在View Model类中,从而使得程序逻辑与视图耦合度降低。
* ViewModel类作为View的DataContext。
* 在MVVM下,所有的事件和动作都被当成命令,如按钮的点击操作,此时不是触发点击事件,而是绑定到一个点击命令,再由命令去执行对应的逻辑。
## 三、使用MVVM模式来实现WPF程序
前面介绍了MVVM一些基础知识,下面通过一个实例来说明下如何在WPF程序中应用MVVM模式。在之前实现WPF程序时,我们可能会把所有的后台逻辑都放在视图的后台文件中,这样的实现方式的好处更直观,方便,对于一些小的应用程序这样做当然没什么问题,但是对于复杂的应用程序这样写的话,可能会导致后台代码显得非常臃肿,到最好变得难以维护。此时想到的解决方案就是职责分离,使后台的逻辑分离到其他类中,MVVM其实我理解就是达到这个目的。下面我们按照MVVM的组成部分来实现下这个MVVM程序。
**第一步:自然是数据部分了,即Model层的实现。在这里定义了一个Person类,其中包含了2个基本的属性。**
为了进行测试,下面创建一个静态方法来获得测试数据。
```
public class PersonDataHelper
{
public static ObservableCollection GetPersons()
{
ObservableCollection samplePersons = new ObservableCollection();
samplePersons.Add(new Person() {Name = "张三", Age = 33});
samplePersons.Add(new Person() { Name ="王五", Age= 22 });
samplePersons.Add(new Person() { Name = "李四", Age = 35 });
samplePersons.Add(new Person() { Name = "LearningHard", Age = 27 });
return samplePersons;
}
}
```
**第二步:实现ViewModel层,实现数据和界面之间的逻辑。**在视图模型类中,包含了属性和命令,因为在MVVM中,事件都当成命令来进行处理,其中命令只能与具有Command属性的控件进行绑定。既然要包含命令,首先就需要实现一个命令,这里自定义的命令需要实现ICommand接口。这里我们定义了一个QueryCommand。具体的实现代码如下所示:
```
public class QueryCommand :ICommand
{
#region Fields
private Action _execute;
private Func _canExecute;
#endregion
public QueryCommand(Action execute)
: this(execute, null)
{
}
public QueryCommand(Action execute, Func canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#region ICommand Member
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (_canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public void Execute(object parameter)
{
_execute();
}
#endregion
}
```
接下来就是定义我们的ViewModel类了,具体的实现代码如下所示:
```
1 public class PersonListViewModel : INotifyPropertyChanged
2 {
3 #region Fields
4 private string _searchText;
5 private ObservableCollection _resultList;
6 #endregion
7
8 #region Properties
9
10 public ObservableCollection PersonList { get; private set; }
11
12 // 查询关键字
13 public string SearchText
14 {
15 get { return _searchText; }
16 set
17 {
18 _searchText = value;
19 RaisePropertyChanged("SearchText");
20 }
21 }
22
23 // 查询结果
24 public ObservableCollection ResultList
25 {
26 get { return _resultList; }
27 set
28 {
29 _resultList = value;
30 RaisePropertyChanged("ResultList");
31 }
32 }
33
34 public ICommand QueryCommand
35 {
36 get { return new QueryCommand(Searching, CanSearching); }
37 }
38
39 #endregion
40
41 #region Construction
42 public PersonListViewModel()
43 {
44 PersonList = PersonDataHelper.GetPersons();
45 _resultList = PersonList;
46 }
47
48 #endregion
49
50 #region Command Handler
51 public void Searching()
52 {
53 ObservableCollection personList = null;
54 if (string.IsNullOrWhiteSpace(SearchText))
55 {
56 ResultList = PersonList;
57 }
58 else
59 {
60 personList = new ObservableCollection();
61 foreach (Person p in PersonList)
62 {
63 if (p.Name.Contains(SearchText))
64 {
65 personList.Add(p);
66 }
67 }
68 if (personList != null)
69 {
70 ResultList = personList;
71 }
72 }
73 }
74
75 public bool CanSearching()
76 {
77 return true;
78 }
79
80 #endregion
81
82 #region INotifyPropertyChanged Members
83
84 public event PropertyChangedEventHandler PropertyChanged;
85
86 #endregion
87
88 #region Methods
89 private void RaisePropertyChanged(string propertyName)
90 {
91 // take a copy to prevent thread issues
92 PropertyChangedEventHandler handler = PropertyChanged;
93 if (handler != null)
94 {
95 handler(this, new PropertyChangedEventArgs(propertyName));
96 }
97 }
98 #endregion
99 }
```
**第三步:实现View层,设计我们的视图,设置它的DataContext属性为ViewModel类**。具体的XAML代码如下所示:
```
```
到此,我们的MVVM的WPF程序就已经完成了,下面就是要看看程序是否达到我们预期的目的。具体的运行结果如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-01-23_56a2eb444aad1.gif)
## 四、总结
到这里,本文的内容就分享完了,并且本文也是WPF系列的最后一篇了,希望这个系列可以使得初学者快速上手WPF编程。在接下来的时间里,我打算写一些具有实战性的内容,因为我之前都是分享一些初级的入门系列,接下来打算分享一些实际的项目实现,以及领域驱动设计方面的内容,希望得到大家的督促和支持。
';