Prism 源码解读4-ViewModel注入
介绍
介绍一个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定位,有几种方法,
- 提前向ViewModelLocationProvider的字典中添加ViewModel的类型
- 改变_defaultViewTypeToViewModelTypeResolver解析方式
- 修改工厂。这个不能从根本上改变。
这个例子用的是第二种。

在程序的开始重写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注入的更多相关文章
- Prism 源码解读1-Bootstrapper和Region的创建
介绍 之前也研究过Prism框架但是一直没有深入理解,现在项目上想把一个Winform的桌面应用程序改造成WPF程序,同时我希望程序是可测试可维护架构良好的,Prism的这些设计理念正好符合我的需求, ...
- Prism 源码解读2-View的加载和控制
介绍 上一篇介绍了Region,这一篇跟Region息息相关,讲一下Region中View的加载方式及控制. 4.ViewDiscovery 在创建好Region后需要将View添加到Region中. ...
- Prism 源码解读3-Modules加载
介绍 在软件开发过程中,总想组件式的开发方式,各个组件之间最好互不影响,独立测试.Prism的Modules很好的满足了这一点. 这个架构图很好了讲解了Prism的Modules的概念 Prism支持 ...
- Prism 源码解读5-数据绑定和命令
介绍 WPF本身就支持通知.绑定和命令,实现ViewModel和VIew之间的通讯,但相对来说功能比较少,Prism扩充了这些功能并提供更加强有力,简洁的数据绑定和命令. 0 绑定通知 WPF的绑定通 ...
- Prism 源码解读6-事件聚合
0 介绍 事件提供的是1对多的绑定,通过委托链实现对订阅者的调用,事件必须要通过发布者调用.同时事件订阅是强引用,事件订阅者的生命周期总是大于等于事件发布者.如果代码中事件很多就会充斥着各种事件的订阅 ...
- Spring-IOC源码解读3-依赖注入
当容器已经载入了BeanDefinition的信息完成了初始化,我们继续分析依赖注入的原理,需要注意的是依赖注入是用户第一次向IOC容器获取Bean的时候发生的,这里有个例外,那就是如果用户在Bean ...
- Prism 源码解读7-导航
介绍 Prism提供了一个非常强大的功能导航,导航的意思就是指定对应的View显示.这个导航的强大之处有: 可以设置导航前后的动作 可以指定View实例的生命周期,可以是否导航到新的View实例 提供 ...
- Alamofire源码解读系列(五)之结果封装(Result)
本篇讲解Result的封装 前言 有时候,我们会根据现实中的事物来对程序中的某个业务关系进行抽象,这句话很难理解.在Alamofire中,使用Response来描述请求后的结果.我们都知道Alamof ...
- nodeJS之eventproxy源码解读
1.源码缩影 !(function (name, definition) { var hasDefine = typeof define === 'function', //检查上下文环境是否为AMD ...
随机推荐
- 神侃:反向激励能救活多少APP?
在很多宣扬互联网企业成功的宣传文案中,为了将其包装地更大高大上和有逼格,总是会将各种心理学术名词用上,以显示自己对市场.用户群体的观察入微.当然事实上所谓的心理学术名词,都是"马后炮&q ...
- SYC极客大挑战部分题目writeup
Welcome 复制黏贴flag即可 我相信你正在与我相遇的路上马不停蹄 关注微信工作号回复"我要flag"即可获得flag 代号为geek的行动第一幕:毒雾初现 发现flag为摩 ...
- PyQt5之俄罗斯方块
上个礼拜有个需求,对csv里的数据按条件进行拆分计算.一想到要做计算,少不了pandas.还有个要求最好是生成命令行工具或者带有界面. 于是尝试下,使用PyQt5做了个简单的UI界面给程序包个壳子,然 ...
- vue-cli2.0项目 添加骨架屏
1.创建项目 npm init webpack project 3.下载 vue-skeleton-webpack-plugin 插件 npm install vue-skeleton-webpa ...
- python基础学习day7
基础数据类型的补充:编码的进阶 str capitalize() 首字母(第一个单词)大写,其余变小写 s1 = 'I LIVE YOU' print(s1.capitalize()) >> ...
- SyntaxError: unexpected character after line continuation character
SyntaxError: unexpected character after line continuation character 待解决问题:在运行.py文件时报错SyntaxError: un ...
- Day1T3小w的魔术扑克——图论
为什么不搞\(T2\)??? 因为我太菜了,那题我是真的搞不出来 题目描述 链接:https://ac.nowcoder.com/acm/contest/1100/C 来源:牛客网 小\(w\)喜欢打 ...
- 【Weiss】【第03章】练习3.22、3.23、3.24:无代码题,栈的思考题
[练习3.22] a.提出支持栈的Push和Pop操作以及第三种操作FindMin的数据结构,其中FindMin 返回该数据结构的最小元素,所有操作在最坏情况下的运行时间都是O(1). b.证明,如果 ...
- annaconda的安装及使用
一.安装 1.安装包下载: 方式1:官网:https://www.anaconda.com/distribution/ 方式2:清华镜像源:https://mirrors.tuna.tsinghua. ...
- 洛谷P5661 公交换乘(CSP-J 2019 T2)
传送门 题目可能排版有问题,导致出现一些乱码,具体请参考洛谷原题 题目描述 著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案: 在搭乘一次地铁后可以获得一张优惠 ...