介绍

介绍一个Prism的MVVM实现,主要介绍Prism如何在WPF上进行的一些封装,以实现MVVM。MVVM到底是什么呢?看一下这一幅经典的图

以前没有ViewModel这个概念,就是将Model传递到View显示,这样软件也可以工作,但却很混乱,一旦VIew要改动,一点点的改动都会造成很多代码需要改动,不利于维护。再者VIew层充斥着各种解析Model的代码,这些代码完全不属于View啊。平白无故的给View增加了很多职责。这是坏代码的味道。所以就有了ViewModel。ViewModel负责干什么,必须要干什么,其实ViewModel的职责就是将自己的数据绑定到View显示,同时数据变化需要通知View,View上客户的操作及时响应,至于数据怎么解析,从哪里获取,View的响应都应该方法后一层,可以是Controller,可以是Servicer,可以是Presenter。也就是业务逻辑尽量推到后一层。

试想一下,系统里的Model有很多,有数据库对应的数据库模型,有业务于对应的领域模型,有用于数据交互的DTO也是模型,那么对应的View有一个ViewModel也不觉得奇怪。

0 ViewModel定位

MVVM的第一步就是要解决ViewModel的依赖注入问题,框架如何不着痕迹的将View对应的VIewModel注入到依赖属性DataContext。

还记得PrismApplicationBase类吗,就是继承Application,将整个Prism框架组件注入到Unity的那个类,

看到第一步是啥?ConfigureViewModelLocator,配置ViewModelLocator,急人之所急,Prism框架的第一步配置ViewModelLocator,

好吧,第一步就是设置ViewModelFactory,这个工厂就是通过View的类型和实例从Unity容器中获取ViewModel实例。

噢!这个View参数还没用上。

再来看看这个包含ViewModelFactory的ViewModelLocationProvider。

从这个名字我们可以大胆猜测,这个类应该是负责真正解析ViewModel的位置的,看到这个类的方法,有ViewModelFactory,有Register,有GetViewModelByXXX。

这个类中一个委托字段_defaultViewTypeToViewModelTypeResolver,从这个字段我们可以看出是默认VIewModel解析方式,可以看出就是把View完整类型名中的Views替换成ViewModels,然后返回Type,从这里面我们知道View的名字一定要含有Views,ViewModel一定要含有ViewModels。

好吧,知道了哪里解析的再来看看哪里调用的。

prism:ViewModelLocator.AutoWireViewModel="True",看到了,将ViewModelLocator的依赖属性AutoWireViewModel至为True,可以进一步推测ViewModelLocator里面肯定调用了ViewModelLocationProvider的相关方法以获得ViewModel的类型或实例。

依赖属性改变触发了AutoWireViewModelChanged方法,然后调用ViewModelLocationProvider.AutoWireViewModelChanged

先去查看两个字典,一个字典key是View是实例,另一个字典key是View的Type,都没有调用,然后调用ViewModelLocationProvider._defaultViewTypeToViewModelTypeResolver,也就是默认解析,在这边解析获得VIewModel的类型,然后通过默认工厂获得ViewModel实例。并绑定到VIew的DataContext。

至此,知道了整个默认VIewModel解析的全部过程,梳理一下

  • 在程序开始向ViewModelLocationProvider中设置ViewModel类型工厂,也就是Unity。
  • ViewModelLocationProvider就是ViewModel获取的地方有两个字典都应该是存放viewmodel,有一个默认解析是通过View的type解析出ViewModel的type。
  • 在Xaml中通过ViewModelLocator的依赖属性AutoWireViewModel调用ViewModelLocationProvider的AutoWireViewModelChanged来实现绑定。

1 自定义ViewModel定位

通过0的介绍,想一下怎么自定义实现VIewModel定位,有几种方法,

  1. 提前向ViewModelLocationProvider的字典中添加ViewModel的类型
  2. 改变_defaultViewTypeToViewModelTypeResolver解析方式
  3. 修改工厂。这个不能从根本上改变。

这个例子用的是第二种。

在程序的开始重写ConfigureViewModelLocator方法,除了向ViewModelLocationProvider中添加ViewModelFactory外,还修改了_defaultViewTypeToViewModelTypeResolver解析方式。直接就通过View的type后面家长ViewModel,简单粗暴。

2 自定义ViewModel解析

这种方法就是上面提到的1方法

  • 提前向ViewModelLocationProvider的字典中添加ViewModel的类型

这张方法显然有很大的弊端,当程序中有很多View时怎么能手动添加呢,只能适用与特殊的View和ViewModel的解析,如Shell的VIewModel的解析。

这种解析方法也不用在意View和ViewModel的名字了。

总结

从ViewModel的解析中,我们看到一种设计模式,View依赖ViewModelLocator,ViewModelLocator依赖ViewModelLocationProvider,ViewModelLocationProvider负责具体解析出对应的实例,相当于ViewModelRegistry,其中当然以有对工厂的依赖。

Prism 源码解读4-ViewModel注入的更多相关文章

  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 源码解读5-数据绑定和命令

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

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

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

  6. Spring-IOC源码解读3-依赖注入

    当容器已经载入了BeanDefinition的信息完成了初始化,我们继续分析依赖注入的原理,需要注意的是依赖注入是用户第一次向IOC容器获取Bean的时候发生的,这里有个例外,那就是如果用户在Bean ...

  7. Prism 源码解读7-导航

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

  8. Alamofire源码解读系列(五)之结果封装(Result)

    本篇讲解Result的封装 前言 有时候,我们会根据现实中的事物来对程序中的某个业务关系进行抽象,这句话很难理解.在Alamofire中,使用Response来描述请求后的结果.我们都知道Alamof ...

  9. nodeJS之eventproxy源码解读

    1.源码缩影 !(function (name, definition) { var hasDefine = typeof define === 'function', //检查上下文环境是否为AMD ...

随机推荐

  1. <pre>标签的使用

    做做笔记.碰见了一个网站,显示代码的时候自带语法高亮,这很新鲜.它的代码被pre标签包裹,原本以为pre标签下的所有的内容会以文本原来的样式输出,特意查了查发现它依然支持html标签. 先来个菜鸟教程 ...

  2. USB小白学习之路(6) IIC EEPROM读取解析

    IIC EEPROM读取解析 1. 编译错误处理(这里可以忽略) 在解压包解压了程序后,直接编译,出现如下错误. *** WARNING L14: INCOMPATIBLE MEMORY MODEL ...

  3. C#编程_单线程IP地址解析

    单线程IP地址解析 目标程序 界面如下图 ​ 设计方法:完成单个IP地址解析,循环调用方法,完成扫描. 注意用stopwatch计算时间. 实现思路 先知道怎么解析一个单个的IP地址. 用循环的方法解 ...

  4. Java 8 Optional 良心指南,建议收藏

    想学习,永远都不晚,尤其是针对 Java 8 里面的好东西,Optional 就是其中之一,该类提供了一种用于表示可选值而非空引用的类级别解决方案.作为一名 Java 程序员,我真的是烦透了 Null ...

  5. 一起了解 .Net Foundation 项目 No.15

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. NUnit Test Fr ...

  6. 单页面和多页面的网页差别比较(SPA)

      单页面应用(singlePAge Web Application) 多页面应用MultiPage Applicaton,MPA) 组成 一个外壳页面和多个页面片段组成 多个完整的页面组成 资源公用 ...

  7. npm项目创建初始过程详解

    npm install 就是安装模块,npm run dev  就是执行npm script中的命令.当我们执行npm命令的时候,它到哪里去找,这就要说到每个node项目中都有的核心文件package ...

  8. springboot连接redis错误 io.lettuce.core.RedisCommandTimeoutException:

    springboot连接redis报错 超时连接不上  可以从以下方面排查 1查看自己的配置文件信息,把超时时间不要设置0毫秒 设置5000毫秒 2redis服务长时间不连接就会休眠,也会连接不上 重 ...

  9. 结题报告--P2441角色属性树

    题目:点此 题目描述 绪萌同人社是一个有趣的组织,该组织结构是一个树形结构.有一个社长,直接下属一些副社长.每个副社长又直接下属一些部长……. 每个成员都有一个萌点的属性,萌点属性是由一些质数的萌元素 ...

  10. 【09】openlayers 图片图层

    效果:  创建地图: var map = new ol.Map({ //设置显示地图的视图 view: new ol.View({ projection:'EPSG:4326',//投影方式 cent ...