一、引言

  在前面介绍了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。大家有兴趣的可以下载源码研究下。

  本文所有源码下载:FristMVVMProject.zip

二、MVVM模式是什么?

  既然讲到MVVM模式,自然第一个问题就是MVVM的含义。MVVM是Model-View-ViewModel的缩写形式,它通常被用于WPF或Silverlight开发。这三者之间的关系如下图所示:

  下面我们分别来介绍下这三部分。

模型(Model)

  Model——可以理解为带有字段,属性的类。

视图(View)

  View——可以理解为我们所看到的UI。

视图模型(View Model)

View Model在View和Model之间,起到连接的作用,并且使得View和Model层分离。View Model不仅仅是Model的包装,它还包含了程序逻辑,以及Model扩展,例如,如果Model中有一个公开属性不需要在UI上显示,此时我们可以不再View Model中去定义它。

在MVVM模式下,WPF程序的运行流程如下图所示:

  在MVVM中,VM的地位可以说是举足轻重。使用MVVM模式具有以下几个特点:

  • 视图的cs文件包括极少的代码,其核心逻辑都被放在View Model类中,从而使得程序逻辑与视图耦合度降低。
  • ViewModel类作为View的DataContext。
  • 在MVVM下,所有的事件和动作都被当成命令,如按钮的点击操作,此时不是触发点击事件,而是绑定到一个点击命令,再由命令去执行对应的逻辑。

三、使用MVVM模式来实现WPF程序

  前面介绍了MVVM一些基础知识,下面通过一个实例来说明下如何在WPF程序中应用MVVM模式。在之前实现WPF程序时,我们可能会把所有的后台逻辑都放在视图的后台文件中,这样的实现方式的好处更直观,方便,对于一些小的应用程序这样做当然没什么问题,但是对于复杂的应用程序这样写的话,可能会导致后台代码显得非常臃肿,到最好变得难以维护。此时想到的解决方案就是职责分离,使后台的逻辑分离到其他类中,MVVM其实我理解就是达到这个目的。下面我们按照MVVM的组成部分来实现下这个MVVM程序。

  第一步:自然是数据部分了,即Model层的实现。在这里定义了一个Person类,其中包含了2个基本的属性。

public class Person{public string Name { get; set; }public int Age { get; set; }}

  为了进行测试,下面创建一个静态方法来获得测试数据。

public class PersonDataHelper{public static ObservableCollection<Person> GetPersons(){ObservableCollection<Person> samplePersons = new ObservableCollection<Person>();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 Fieldsprivate Action _execute;private Func<bool> _canExecute;#endregion public QueryCommand(Action execute): this(execute, null){ }public QueryCommand(Action execute, Func<bool> canExecute){if (execute == null)throw new ArgumentNullException("execute");_execute = execute;_canExecute = canExecute;}#region ICommand Memberpublic 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<Person> _resultList;
 6         #endregion
 7
 8         #region Properties
 9
10         public ObservableCollection<Person> 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<Person> 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<Person> personList = null;
54             if (string.IsNullOrWhiteSpace(SearchText))
55             {
56                 ResultList = PersonList;
57             }
58             else
59             {
60                 personList = new ObservableCollection<Person>();
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代码如下所示:

<Window x:Class="MVVMDemo.View.PersonsView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:MVVMDemo.ViewModel"Title="PersonsView" Height="350" Width="400"><!--设置DataContex是ViewModel类,当然你也可以使用后台代码设置--><Window.DataContext><local:PersonListViewModel /></Window.DataContext><Grid><Grid.RowDefinitions><RowDefinition Height="50"/><RowDefinition Height="*"/></Grid.RowDefinitions><TextBox Grid.Row="0" Name="searchtxt" Text="{Binding  Path=SearchText, Mode=TwoWay}" HorizontalAlignment="Left" Height="30" Width="280" Margin="10,0,0,0"></TextBox><Button Grid.Row="0" Name="searchBtn" Content="Search" Command="{Binding Path=QueryCommand}" Width="80" Height="30" HorizontalAlignment="Right" Margin="0,0,10,0"></Button><DataGrid Grid.Row="1" Name="datGrid" HorizontalAlignment="Center"VerticalAlignment="Top" ItemsSource="{Binding Path=ResultList}" Width="300"></DataGrid></Grid>
</Window>

  到此,我们的MVVM的WPF程序就已经完成了,下面就是要看看程序是否达到我们预期的目的。具体的运行结果如下图所示:

四、总结

  到这里,本文的内容就分享完了,并且本文也是WPF系列的最后一篇了,希望这个系列可以使得初学者快速上手WPF编程。在接下来的时间里,我打算写一些具有实战性的内容,因为我之前都是分享一些初级的入门系列,接下来打算分享一些实际的项目实现,以及领域驱动设计方面的内容,希望得到大家的督促和支持。

WPF快速入门系列(8)——MVVM快速入门相关推荐

  1. Silverlight入门系列]使用MVVM模式

    [Silverlight入门系列]使用MVVM模式(9): 想在ViewModel中控制Storyboard动画? (2011-09-07 16:12) [Silverlight入门系列]使用MVVM ...

  2. 【快速搭建系列】idea快速搭建SSH2框架(struts2+spring5+hibernate5)

    [快速搭建系列]idea快速搭建SSH2框架(struts2+spring5+hibernate5) 压了很久的文,都差点忘记了 网上关于SSH的框架教程五花八门的,自己踩了一周多的坑说什么也要搞一个 ...

  3. k8s入门系列之guestbook快速部署

    k8s集群以及一些扩展插件已经安装完毕,本篇文章介绍一下如何在k8s集群上快速部署guestbook应用. •实验环境为集群:master(1)+node(4),详细内容参考<k8s入门系列之集 ...

  4. python语言入门m-「数据挖掘入门系列」Python快速入门

    Python环境搭建 本次入门系列将使用Python作为开发语言.要使用Python语言,我们先来搭建Python开发平台.我们将基于Python 2.7版本.以及Python的开发发行版本Anaco ...

  5. Windows Azure 入门系列课程Windows Azure 入门系列课程

    Windows Azure 入门系列课程 https://www.microsoft.com/china/msdn/events/webcasts/shared/webcast/NewSeries/A ...

  6. qt设置顶层窗口_Python快速入门系列:PyQt5 快速开发GUI-窗口类型以及主窗口创建...

    QMainWindow, QWidget, QDialog三个类都是用来创建窗口的,可以直接使用或继承后再使用.QMainWindow窗口可以包含菜单栏.工具栏.状态栏.标题栏等,是最常见的窗口形式, ...

  7. Laravel5.8入门系列二,快速实现用户注册登录功能

    一 XAMPP 环境配置 这次我们需要开始使用继承开发环境了,因为我们需要使用数据库,完成用户的登录注册功能. 首先要配置好XAMPP环境,我们需要添加一个vhost,指向blog5.8的public ...

  8. [Silverlight入门系列]使用MVVM模式(6):使用Behavior

    Behavior把一些常用的行为封装成可重复使用的组件(Component),在理想状况下,Designer(设计师)或domain expert(特定领域的专家,例如财会人员.HR人员.或MIS)甚 ...

  9. Silverlight入门系列]使用MVVM模式(1):MVVM核心概念

    MVVM模式是Model.View.ViewModel的简称,最早出现在WPF,现在Silverlight中也使用该模式,MVVM模式是对MVC模式的变种.哪儿变了?我认为MVVM和MVC的主要变化在 ...

最新文章

  1. 有趣的计算机课的作文,有趣的电脑课作文500字
  2. ATS无法缓存QQ音乐的音频文件问题
  3. 开发vs测试 | 每日趣闻
  4. difference between JSON Model and client model
  5. RuoYi-Cloud 进阶篇_03( Seata 高可用集群与 NacosConfig配置中心整合)
  6. 禁止chrome浏览器自动填充表单的解决方案
  7. Ubuntu16.04 安装LaTex并配置中文环境
  8. js获取日期选择器值html,利用Query+bootstrap和js两种方式实现日期选择器
  9. api arx autocad_应用ARX实现基于AutoCAD平台的参数化绘图
  10. “疫情当下”能做什么?PHP直播系统源码在行动
  11. 基于SSM医院预约管理系统
  12. STM32CubeMX驱动4脚OLED模块
  13. 什么是云计算,云计算的基本原理是什么?
  14. 计算机的排版方法,计算机编辑排版系统及其方法
  15. 常见软件架构风格介绍
  16. 域名注册和抢注等域名投资知识
  17. npoi 删除多行 操作excel_NPOI操作EXCEL 【只争朝夕】
  18. Swift - 访问通讯录-使用AddressBook.framework和AddressBookUI.framework框架实现
  19. 软件测试中的正交缺陷分析总结,正交缺陷分类(ODC)流程简介及应用经验分享(上)...
  20. 一个整人的vbs脚本(yzy原创)

热门文章

  1. MySQL优化学习总结
  2. C# 操作Sql Server 学习总结
  3. python多线程的两种写法
  4. oc 计算 带括号 式子
  5. 2017.8.12 联考题
  6. jquery生成二维码
  7. Fuel 30 分钟快速安装OpenStack
  8. X264编码流程详解(转)
  9. C++ 多态实现机制
  10. OnlineJudge在线判题系统