在WPF开发中,经典的编程模式是MVVM,是为WPF量身定做的模式,该模式充分利用了WPF的数据绑定机制,最大限度地降低了Xmal文件和CS文件的耦合度,也就是UI显示和逻辑代码的耦合度,如需要更换界面时,逻辑代码修改很少,甚至不用修改。与WinForm开发相比,我们一般在后置代码中会使用控件的名字来操作控件的属性来更新UI,而在WPF中通常是通过数据绑定来更新UI;在响应用户操作上,WinForm是通过控件的事件来处理,而WPF可以使用命令绑定的方式来处理,耦合度将降低,WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI。本教程的第15到19简单介绍了数据绑定的简单应用

一、MVVM介绍

  MVVM是Model-View-ViewModel(模型-视图-视图模型)的缩写形式,它通常被用于WPF或Silverlight开发。我们可以通过下图来直观的理解MVVM模式:

1、View就是xaml界面,也就是那个扩展名为xaml的文件,它负责与用户交互,接收用户输入,把数据展现给用户。

2、ViewModel就是一个C#类,负责收集需要绑定的数据和命令,通过View类的DataContext属性绑定到View,同时也可以处理一些UI逻辑。

3、Model,就是数据库系统中的实体对象,可包含属性和行为。

  三者之间的关系:View对应一个ViewModel,ViewModel可以聚合N个Model,ViewModel可以对应多个View

二、MVVM的优势

MVVM的根本思想就是界面和业务功能进行分离,View的职责就是负责如何显示数据及发送命令,ViewModel的功能就是如何提供数据和执行命令。各司其职,互不影响。在实际的业务场景中我们经常会遇到客户对界面提出建议要求修改,使用MVVM模式开发,当设计的界面不满足客户时,我们仅仅只需要对View作修改,不会影响到ViewModel中的功能代码,减少了犯错的机会。随着功能地增加,系统越来越复杂,相应地程序中会增加View和ViewModel文件,将复杂的界面分离成局部的View,局部的View对应局部的ViewModel,功能点散落在各个ViewModel中,每个ViewModel只专注自己职能之内的事情。ViewModel包含了View要显示的数据,并且知道View的交互代码,使用MVVM架构具有以下优势:

1、易维护 2、灵活扩展3、易测试  4、用户界面设计师与程序开发者能更好的合作

三、MVVM简单示例

1、在项目的model文件创建类Emp及EmpViewModel,内容如下:

注意这个EmpViewModel叫“视图模型”,通过数据绑定将它们绑在一起,它真的是一个很好的适配器能将模型变成某种WPF框架可以使用的东西。所以这个就是MVVM中的VM,而Emp是M,同在缺少V。

2、在control文件夹中添加窗口MVVMWindow1.xaml,具体内容如下:

<Window x:Class="WpfApp6.control.MVVMWindow1"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WpfApp6.control"xmlns:vm="clr-namespace:WpfApp6.model"mc:Ignorable="d"Title="MVVM简单介绍" Height="450" Width="800"><!--窗口的上下文声明一个EmpViewModel的实例,前面必须定义vm这个命名空间--><Window.DataContext><vm:EmpViewModel></vm:EmpViewModel></Window.DataContext><Window.Resources><!--声明样式--><Style x:Key="st1"><Setter Property="Control.FontSize" Value="17"></Setter></Style></Window.Resources><Grid  Style="{StaticResource st1}" ><Button  Content="更新" HorizontalAlignment="Left" Margin="180,256,0,0" VerticalAlignment="Top" Width="145" Click="Button_Click"/><Label Content="用户:" HorizontalAlignment="Left" Margin="112,110,0,0" VerticalAlignment="Top" RenderTransformOrigin="7.256,0.582"/><!--Binding绑定视图模型中的UserName和CompanyName--><TextBox  HorizontalAlignment="Left" Height="23" Margin="205,110,0,0" TextWrapping="Wrap" Text="{Binding UserName}" VerticalAlignment="Top" Width="120"/><TextBox HorizontalAlignment="Left" Height="23" Margin="555,110,0,0" TextWrapping="Wrap" Text="{Binding CompanyName}" VerticalAlignment="Top" Width="120"/><Label Content="公司:" HorizontalAlignment="Left" Margin="393,110,0,0" VerticalAlignment="Top"/></Grid>
</Window>

3、MVVMWindow1.xaml.cs后台代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WpfApp6.model;namespace WpfApp6.control
{/// <summary>/// MVVMWindow1.xaml 的交互逻辑/// </summary>public partial class MVVMWindow1 : Window{EmpViewModel empvm ;public MVVMWindow1(){InitializeComponent();empvm = base.DataContext as EmpViewModel;}/// <summary>/// 单击按钮/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void Button_Click(object sender, RoutedEventArgs e){empvm.UserName = "欧阳克";empvm.CompanyName = "华山庄";}}
}

4、启动程序,记得将项目启动文件App.xaml中的启动项改为 StartupUri="control/MVVMWindow1.xaml",运行结果,点击按钮时,不会有任何反应

这里我们点击更新按钮不会有任何反应,因为还没有实现数据绑定。此时视图不会收到任何的关于属性改变的通知。要解决这个问题我们必须实现名称为INotifyPropertyChanged的接口。任何实现了这个接口的类,当属性发生改变的时候会通知所有监听者,所以我们需要修改视图模型NameViewModel类,完整代码是:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace WpfApp6.model
{/// <summary>/// 页面视图模型,实现INotifyPropertyChanged接口/// </summary>public class EmpViewModel:INotifyPropertyChanged{//构造方法public EmpViewModel(){emp = new Emp() { UserName = "杨康", CompanyName = "上海金财" };}//私有字段 private Emp emp;//公共属性public string UserName{get { return emp.UserName; }set { emp.UserName = value;RaisePropertyChanged("UserName"); }}// 属性值发生更改时触发的属性public event PropertyChangedEventHandler PropertyChanged; //属性更改方法private void RaisePropertyChanged(string propertyName){ if (PropertyChanged != null){PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));}}public string CompanyName{get { return emp.CompanyName; }set { emp.CompanyName = value; RaisePropertyChanged("CompanyName"); }}}
}

注意视图模型类实现了INotifyPropertyChanged接口,即通知属性更改,每个属性中增加了代码RaisePropertyChanged,这个方法就是属性更改时的方法,并且定义了一个事件属性,即public event PropertyChangedEventHandler PropertyChanged;其他代码没有变,运行后,点击更新效果是:

这里说明UI同步更新了,关键在于INotifyPropertyChanged,但是上面的方法还有不足,那就是假如有多个model需要设置属性更改,那工作量是蛮麻烦和巨大的,这里需要改进方法,定义一个基类,让基类实现INotifyPropertyChanged,让用户类继续基类,具体操作是:

5、在model中添加类ViewModelBase,代码是:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;namespace WpfApp6.model
{/// <summary>/// 模型视图其类/// </summary>public class ViewModelBase : INotifyPropertyChanged{/// <summary>/// 属性值发生更改时触发/// </summary>public event PropertyChangedEventHandler PropertyChanged;/// <summary>/// 执行更改/// C#5.0中的新特性CallerMemberName/// </summary>/// <param name="propertyName"></param>protected void OnPropertyChanged([CallerMemberName] string propertyName = ""){if (PropertyChanged != null){PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));}}}
}

6、在model创建另一个类,EmpViewModel2,代码 是:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace WpfApp6.model
{/// <summary>/// 继承基类ViewModelBase/// </summary>public class EmpViewModel2:ViewModelBase{public EmpViewModel2(){emp = new Emp() { UserName = "杨康", CompanyName = "上海金财" };}//私有字段 private Emp emp;//公共属性public string UserName{get { return emp.UserName; }set { emp.UserName = value; OnPropertyChanged(); }}public string CompanyName{get { return emp.CompanyName; }set { emp.CompanyName = value; OnPropertyChanged(); }}}
}

6、修改MVVMWindow1.xaml文件的一个地方,即改成以下内容,表示现在窗口的上下文使用EmpViewModel2,也就是上面第5步的视图模型,而不是原来的EmpViewModel,其他都不要改

7、修改MVVMWindow1.xaml.cs代码,如图

8、运行程序,效果如下:

小结,我们在实际项目中应该使用后面定义基类的方式去实现属性的绑定,这才是对的。

操作起来6666,棒棒哒。

WPF真入门教程23--MVVM简单介绍相关推荐

  1. WPF真入门教程02--新建WPF工程

    在VS开发环境安装完成之后,首先我们先新建一个WPF工程,然后对工程目录结构啥的要有所了解才行. 打开VS2019 工程建好之后,WPF应用程序"会在"引用"里面自动添加 ...

  2. WPF真入门教程03--XAML介绍

    一.窗体类基本概念 对于WPF应用程序,在Visual Studio和Expression Blend中,自定义的窗体均继承System.Windows.Window类.用户通过窗口与 Windows ...

  3. WPF真入门教程21--WPF资源系统

    WPF资源系统是一种保管一系列对象(如常用的画刷.样式或模版)的简单办法,从而使您更容易地复用这些对象. WPF允许在代码中以及在标记中的各个位置定义资源(如特定的控件或窗口或在整个应用程序中定义). ...

  4. WPF真入门教程20--数据排序

    如果想以特定的方式对数据进行排序,可以绑定到 CollectionViewSource,而不是直接绑定到 ObjectDataProvider.CollectionViewSource 则会成为数据源 ...

  5. WPF真入门教程04--UI布局1

    大家都知道:UI是做好一个软件很重要的因素,如果没有一个漂亮的UI,功能做的再好也无法吸引很多用户使用,而且没有漂亮的界面,那么普通用户会感觉这个软件没有多少使用价值. WPF系统基于流布局的标准,开 ...

  6. WPF真入门教程22--样式应用

    1.什么是样式 WPF相较于以前学的WinForm,WPF在UI设计与动画方面的炫丽是最吸引我来学习的.在WPF中XMAL代码的引入使得代码的编写能够前后端分离,为获得更好的界面,也使得我们不得不分出 ...

  7. WPF真入门教程12--ListView控件

    ListView 控件在Windows应用程序中常用,用于表示数据列表.如果您以前使用过 WinForms,那么您对ListView的实用性有一个很好的了解,但您应该意识到 WPF中的ListView ...

  8. WPF真入门教程01--WPF简介

    Windows Presentation Foundation (简称 WPF),WPF是微软推出的基于Windows 的用户界面框架,属于.NET Framework 3.0的一部分.它提供了统一的 ...

  9. WPF自学入门(十一)WPF MVVM模式Command命令 WPF自学入门(十)WPF MVVM简单介绍...

    WPF自学入门(十一)WPF MVVM模式Command命令 在WPF自学入门(十)WPF MVVM简单介绍中的示例似乎运行起来没有什么问题,也可以进行更新.但是这并不是我们使用MVVM的正确方式.正 ...

最新文章

  1. 华为深度学习新模型DeepShift:移位和求反代替乘法,成本大降
  2. mysql 指定日期条件求和_如何在mysql中按每个日期对字段进行求和-问答-阿里云开发者社区-阿里云...
  3. 关于scrollTop为0以及解决方法
  4. mysql模板标签数据库设计_MySQL数据库规范化设计
  5. 自动驾驶场景解析:图像分割开发实战
  6. Oracle闪回技术(Flashback)
  7. STM32的位带操作
  8. 使用ln命令创建软引用(相对路径与绝对路径)
  9. 渗透测试之敏感信息收集
  10. 财帮子,一个非常不错的投资理财社区
  11. 错误: 找不到或无法加载主类的解决办法
  12. 吉林大学邮箱smtp服务器,吉珠专属EDU邮箱上线,校友也可申请!除了发邮件,这个邮箱还能省钱!...
  13. 获取win10计算机所有权限,如何获得管理员权限 教您win10获取管理员所有权限的方法。...
  14. 【网络】交换机 VLAN 网关 路由器
  15. 吉大C语言程序设计作业,吉大19年9月《C语言程序设计》作业考核试题答案
  16. java arraylist的个数_java – ArrayList的限制
  17. 使用Python获取指定Windows凭证账户密码
  18. 天气转晴东方木开始学习IT知识学习篇之一
  19. 文件域跟图像域-制作QQ主页信息
  20. NEON技术如何实现移动端视频高效解码AV1?

热门文章

  1. 统信UOS安装 执行 curl命令
  2. 大学计算机信息知识题库,大学生计算机基础知识选择题库
  3. 求生之路2不显示局域网服务器,求生之路2怎么局域网联机 求生之路2局域网联机教程...
  4. 计算机病毒的格式是什么样的,文件病毒的格式是什么
  5. 深入WindowsME之系统还原(转)
  6. expect 使用实例
  7. docker本地镜像下载及加载
  8. 2021 Java面试题总结,附答案(个人遇到面试题汇总)
  9. index.jsp模板(约束)
  10. FPS游戏原理漫谈:玩家延时与服务器同步