介绍

WPF本身就支持通知、绑定和命令,实现ViewModel和VIew之间的通讯,但相对来说功能比较少,Prism扩充了这些功能并提供更加强有力,简洁的数据绑定和命令。

0 绑定通知

WPF的绑定通知需要实现INotifyPropertyChanged接口,也就是实现一个属性改变事件,用来通知UI属性改变了,让UI更新。该事件需要一个事件参数new PropertyChangedEventArgs(propertyName)传入属性的名字,这样的调用方式比较繁琐。

Prism扩充了WPF的绑定通知。提供了BindableBase 实现了 INotifyPropertyChanged接口,并使用CallerMemberName获取属性名字。这样就解决了属性改变事件调用繁琐的问题。同时在内部还是对相等值进行了过滤。

简单愉快的调用吧

只需要使用SetProperty方法就可以自动更新UI了。

值得注意的是OnPropertyChanged还提供了对Expression的支持

也就是主动调用OnPropertyChanged(()=>this.PropertyName),也可以触发UI响应。

1 命令

DelegateCommand

WPF命令和通知有点类似,命令需要实现ICommand接口,实现Execute方法,命令状态CanExecute和命令状态改变事件。并且WPF只实现了一个RoutedCommand。Prism提供了一个DelegateCommandBase命令基类实现ICommand,并扩充了子类DelegateCommand,大大简化了命令调用方式

看到在基类中有_synchronizationContext线程同步上下文,用来保证命令执行的时候线程同步。

重点关注一下子类中的几个方法

1.ExecuteDelegateCommand = new DelegateCommand(Execute, CanExecute);

  • 这个命令声明方式,如果命令状态发生变化的时候需要主动调用RaiseCanExecuteChanged方法来触发命令状态改变事件。

2.DelegateCommandObservesProperty = new DelegateCommand(Execute, CanExecute).ObservesProperty(() => IsEnabled);

  • 可以看到这种声明方式,提供了一个ObservesProperty方法,不需要显示调用命令状态改变事件。

3.DelegateCommandObservesCanExecute = new DelegateCommand(Execute).ObservesCanExecute(() => IsEnabled);

  • 这种声明方法提供ObservesCanExecute方法,直接观测命令状态改变事件和属性。

4.ExecuteGenericDelegateCommand = new DelegateCommand(ExecuteGeneric).ObservesCanExecute(() => IsEnabled);

  • 这是一个使用泛型带参数的声明方式,

看一下内部怎么实现这种简单而强大的功能

通过Expression,内部调用PropertyObserver.Observes()方法并将RaiseCanExecuteChaned方法传入。

在PropertyObserver将Expression保存在一个链表,并每个节点都订阅OnPropertyChanged事件。

CompositeCommand

Prism还提供了一个CompositeCommand命令

这个命令的功能跟其名字一样,就是复合命令,命令集合。

  • 将DelegateCommand实例放到其中,每当调用CompositeCommand调用的时候会调用它保存的所有命令,
  • 命令集合中任何一个命令状态改变,都会触发CompositeCommand命令状态的改变事件,导致CompositeCommand检查集合中所有的命令状态,首先会检查IActiveAware,再检查命令状态,如果任何一个命令状态是False,都会导致组合命令返回False

来看一下源码

注意到,聚合命令也是通过线程上下文保持线程同步,同时看到有检测IActiveAware接口,这个接口是什么意思呢?其实就是查看该命令是否激活。这个接口有一个激活状态属性和一个激活状态改变事件,

只要界面主动调用UpdateCommand.IsActive = true;命令就会被激活并触发复合命令的激活状态改变回调函数

在复合命令的ShouldExcute方法中检查其激活状态,命令集合中没有激活命令,那么复合命令的执行状态也会改变。

命令执行和激活状态都是差不多的接口,有状态和状态改变事件组成,感觉很多地方都有相似的模式,有点像订阅模式,也有点像状态机,包括一些Collection和Storage.

总结

主要讲了下Prism提供的绑定通知和命令,学习到如何在WPF框架基础上做一些封装,如果可能甚至可以自己重新封装一些功能更强大的命令来兼容Prism。

Prism 源码解读5-数据绑定和命令的更多相关文章

  1. Prism 源码解读1-Bootstrapper和Region的创建

    介绍 之前也研究过Prism框架但是一直没有深入理解,现在项目上想把一个Winform的桌面应用程序改造成WPF程序,同时我希望程序是可测试可维护架构良好的,Prism的这些设计理念正好符合我的需求, ...

  2. Prism 源码解读2-View的加载和控制

    介绍 上一篇介绍了Region,这一篇跟Region息息相关,讲一下Region中View的加载方式及控制. 4.ViewDiscovery 在创建好Region后需要将View添加到Region中. ...

  3. Prism 源码解读3-Modules加载

    介绍 在软件开发过程中,总想组件式的开发方式,各个组件之间最好互不影响,独立测试.Prism的Modules很好的满足了这一点. 这个架构图很好了讲解了Prism的Modules的概念 Prism支持 ...

  4. Prism 源码解读4-ViewModel注入

    介绍 介绍一个Prism的MVVM实现,主要介绍Prism如何在WPF上进行的一些封装,以实现MVVM.MVVM到底是什么呢?看一下这一幅经典的图 以前没有ViewModel这个概念,就是将Model ...

  5. Prism 源码解读6-事件聚合

    0 介绍 事件提供的是1对多的绑定,通过委托链实现对订阅者的调用,事件必须要通过发布者调用.同时事件订阅是强引用,事件订阅者的生命周期总是大于等于事件发布者.如果代码中事件很多就会充斥着各种事件的订阅 ...

  6. Prism 源码解读7-导航

    介绍 Prism提供了一个非常强大的功能导航,导航的意思就是指定对应的View显示.这个导航的强大之处有: 可以设置导航前后的动作 可以指定View实例的生命周期,可以是否导航到新的View实例 提供 ...

  7. Laravel 源码解读系列第四篇-Auth 机制

    前言 Laravel有一个神器: php artisan make:auth 能够快速的帮我们完成一套注册和登录的认证机制,但是这套机制具体的是怎么跑起来的呢?我们不妨来一起看看他的源码.不过在这篇文 ...

  8. php-msf 源码解读【转】

    php-msf: https://github.com/pinguo/php-msf 百度脑图 - php-msf 源码解读: http://naotu.baidu.com/file/cc7b5a49 ...

  9. create-react-app源码解读之为什么不搞个山寨版的create-react-app呢?

    最近把 vue-cli@2.x 和 create-react-app 的源码都看了一遍.由于现在官方推荐使用 vue-cli@3.0 ,改动比较大,所以就不写关于 vue-cli 的了(据说是因为 v ...

随机推荐

  1. CSS3:TEXT-SHADOW|BOX-SHADOW(炫彩字体)

    2016年2月26日个人博客文章--迁移到segmentfault (1)text-shadow(文本阴影) 在介绍css3:text-shadow文本阴影之前,我们先来看看用它都能实现什么效果: 没 ...

  2. Python爬虫 - UserAgent列表

    PC端: PC_USER_AGENT = [ 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', 'Mozilla/4.0 (compatibl ...

  3. 简单谈谈HashMap

    概述 面试Java基础,HashMap可以说是一个绕不过去的基础容器,哪怕其他容器都不问,HashMap也是不能不问的. 除了HashMap,还有HashTable跟ConcurrentHashMap ...

  4. oracle的wm_concat函数实现行转列

    有以下数据 deptname phone username isboss 部门A 电话1 员工A 0 部门A 电话1 领导A 1 部门B 电话2 员工B 0 部门B 电话2 员工C 0 部门B 电话2 ...

  5. OpenCV中Mat的基本用法:创建、复制

    OpenCV中Mat的基本用法:创建.复制 一.Mat类的创建: 1.方法一: 通过读入一张图像,直接将其转换成Mat对象. Mat image = imread("test.jpg&quo ...

  6. mongoose基本增删改查

    1.安装 打开命令行 npm i mongoose 2.连接数据库 // 引入安装的包 var mongoose = require('mongoose'); mongoose.connect('mo ...

  7. 如何搭建自己的SpringBoot源码调试环境?--SpringBoot源码(一)

    1 前言 这是SpringBoot2.1源码分析专题的第一篇文章,主要讲如何来搭建我们的源码阅读调试环境.如果有经验的小伙伴们可以略过此篇文章. 2 环境安装要求 IntelliJ IDEA JDK1 ...

  8. VsCode从零开始配置一个属于自己的Vue开发环境

    vscode vue VsCode算是比较热门的一个代码编辑器了,全名Visual Studio Code下载地址:点我去下载插件众多,功能齐全,我在平常开发过程中都是用的它,整理了些自认好用的插件, ...

  9. SyntaxError: unexpected character after line continuation character

    SyntaxError: unexpected character after line continuation character 待解决问题:在运行.py文件时报错SyntaxError: un ...

  10. 曹工杂谈:花了两天时间,写了一个netty实现的http客户端,支持同步转异步和连接池(1)--核心逻辑讲解

    背景 先说下写这个的目的,其实是好奇,dubbo是怎么实现同步转异步的,然后了解到,其依赖了请求中携带的请求id来完成这个连接复用:然后我又发现,redisson这个redis客户端,底层也是用的ne ...