WPF学习笔记5:MVVM
2021-09-04 13:37:13一、了解MVVM
1. 什么是MVVM
-
一种设计模式
-
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
-
为什么需要MVVM?解决什么问题?
-
降低耦合、独立开发、逻辑重用(Xamarin MAUI多平台应用)、可测试
-
响应式布局
-
2. 控件交互到MVVM模式的转变
- 控件交互:基于控件的功能开发
- -**MVVM**模式
- 代码/项目结构
- Models:
- Views:
- ViewModels:
3. MVVM绑定模式下的信息交互
- 数据类型:INotifyPropertyChanged接口
- public event PropertyChangedEventHandler? PropertyChanged;
- 执行事件,发公告
- ContextMenu,注意:命令的数据源的指定
- 行为动作:ICommand接口
- public event EventHandler? CanExecuteChanged;
- public bool CanExecute(object? parameter)
- public void Execute(object? parameter)
- 是不是所有控件都有Command属性?是不是所有动作都可以使用Command?
- 无法绑定的动作如何处理?
4. MVVM绑定扩展
-
无法绑定的对象属性
- 通过附加属性进行扩展
-
无法绑定的动作事件
-
(InputBindings:
) -
单击鼠标左键 :LeftClick 双击鼠标左键:LeftDoubleClick
-
单击鼠标中键 :MiddleClick 双击鼠标中键:MiddleDoubleClick
-
单击鼠标右键:RightClick 双击鼠标右键:RightDoubleClick
-
不执行任何操作:None 旋转鼠标滚轮:WheelClick
-
-
事件转命令
- Behavior
- 自定义实现
5. MVVM案例
- 一般页面信息绑定
- 页面集合绑定
- 任意数据源绑定
- 自定义控件
6. MVVM分层逻辑相关问题
-
VM逻辑中弹窗操作
- 应用中逻辑处理过程中需要打开一个子窗口,作为Dialog窗口进行信息显示
- 利用一个第三方对象WindowProvider,允许View层进行窗口对象的注册 ,允许ViewModel层进行窗口对象的调用请求
- 过程中涉及两方的数据传递
-
任意对象间逻辑调用
- 委托对象的管理,被动方进行委托方法的注册,主动方进行委托方法的请求调用
- 核心 :委托对象的使用
7.常用框架
- MvvmLight
- CommunityToolkit.MVVM
- Prism
- Caliburn.Micro
- Cinch
- MVVMFoundation
- nRoute
二、MvvmLight
1. 关于
- 停止更新
- 官网:http://www.mvvmlight.net/
- 源码地址:https://github.com/lbugnion/mvvmlight、https://archive.codeplex.com/?p=mvvmlight(迁移到Github)
2. 开始
- 引入相关库MvvmLight、MvvmLightLibs
3. 框架中的数据与行为
-
数据绑定与通知:INotifyPropertyChanged
- 默认:自定义
- 框架:ObservableObject、ViewModelBase(VM的资源释放)
-
**命令绑定对象:**ICommand
- 默认:自定义
- 框架:RelayCommand、RelayCommand<T>
4. 扩展对象
-
Messenger:解决对象间的逻辑调用(使得VM可以调用View层面的对象)
- 注册(委托方法)、发布(主动请求执行这个委托方法)、反注册
-
DispatcherHelper
- 跨线程、初始化、应用中任意地方调用
-
SimpleIoC
- IoC处理
- 代码结构升级
- 好处:框架-IOC 耦合度 功能修改的更方便
三、CommunityToolkit.MVVM
1. 介绍
- MVVM工具包,以前名为 Microsoft.Toolkit.Mvvm 由 Microsoft 维护和发布,是 .NET Foundation 的一部分。
- 支持:.NET Standard 2.0、 .NET Standard 2.1 和 .NET 6 (UI Framework 不可知,基本使用没有问题/编译特性用不了)
- 安装:Nuget -> CommunityToolkit.MVVM
2. 常规对象
- ObservableObject
- RelayCommand/RelayCommand<T>
- Messenger:WeakReferenceMessenger/StrongReferenceMessener
- IOC:默认这个工具包中没有IoC对象,建议使用 ServiceCollection
3. 扩展对象
- 特性 / ObservableValidator
- AsyncRelayCommand
- Message相关/ ObservableRecipient
四、Prism框架
1. 框架中的数据与行为
- BindableBase
- DelegateCommand/DelegateCommand<T>
2. 基本逻辑处理
- IOC:项目初始化,Unity、DryIoc
- 属性注入、参数多实现注入
- 消息与弹窗 View-》DataContext明确赋值
3. 消息对象(事件总线)
- 注入IEventAggregator
- 定义消息对象
- 订阅与发布
- 订阅参数:主要委托方法、消息过滤条件、消息委托的引用方式、多线程状态控制
4. 弹窗对象
- 创建一个弹出窗口的内容:一般是UserControl(不是Window)
- 注入:IDialogService 用来执行弹窗动作,一般注入到某个VM中调用
- 注册弹窗内容(内容需要注册到IoC容器),对应ViewModel实现 IDialogAware 接口
- 窗口配置:在内容UserControl对象中,进行样式设置 p:Dialog.WindowStyle
- 注册弹窗窗口,对应窗口实现 IDialogWindow 接口
5. ViewModel的自动匹配
- 标准状态:
- ViewModel与视图类型位于同一个程序集中
- ViewModel位于.ViewModels(ViewModel)子命名空间中
- View位于.Views(View)子命名空间中
- ViewModel名称与视图名称对应,以“ViewModel”结尾
- 个性化配置:
- 在启动位置(PrismApplication/PrismBootstrapper)重写ConfigureViewModelLocator方法
- ViewModelLocationProvider: (1)更改命名约定 (2)独立注册-4种方式
6. 区域化
- Shell
- 区域注册
- 项目初始化
- 页面初始化:窗口(Shell)里进行区域划分,区域需要注册到RegionManager里的,才能进行内容接收
- 注入:IRegionManager:管理项目中所有的Region区域的,处理区域中内容显示逻辑
- 注册导航页面:regionManager.RegisterViewWithRegion("ViewRegion", "ViewA");
- 执行导航动作,传参
- 观察导航过程:接收参数,页面对应的ViewModel实现INavigationAware接口
- 观察导航页面生命周期:控制页面是否自动销毁,页面对应ViewModel实现
- IRegionMemberLifetime接口
- 确认是否允许从当前页面导航出去:页面对应ViewModel实现IConfirmNavigationRequest接口
- IRegionNavigationJournal(接收对象)、IJournalAware(实现)、View中的区域注册(不是Shell)、复合命令
7. 模块化
- 项目的分模块管理
- 模块定义,创建WPF类库,添加类对象,实现IModule接口
- 模块注册
- 项目初始化类中添加(配置文件、类型添加、自动扫描)
- 模块懒加载
- 模块动态热加载
8. 区域化总结
-
Shell与Region
Region的作用:确定功能区域;确保交互页面的内容更新
-
Region的注册:
- ContentControlRegionAdapter
- ItemsControlRegionAdapter
- SelectorRegionAdapter
- TabControlRegionAdapter
- 自定义Region
-
Region与Navigation
- 基本导航过程(3种方式):AddToRegion、RequestNavigate、RegisterViewWithRegion
- 导航生命周期:IRegionMemberLifetime、RegionMemberLifetime特性
- 导航确认:IConfirmNavigationRequest
- 导航传参:INavigationAware
- 导航日志:IRegionNavigationService、IJournalAware
9. 总结
-
Shell、Region、Module
Module是功能和资源的逻辑集合,其打包方式可以单独开发、测试、部署并集成到应用程序中。
-
Module的定义
每个模块都有一个中心类,负责初始化模块并将其功能集成到应用程序中。 IModule
-
Module的注册与发现
注册发现:代码注册、配置文件注册、XML文件注册、目录扫描
Module依赖、按需加载
-
已实现,直接注入使用
IUnityContainer、IContainerExtension、IContainerProvider、IContainerRegistry、IModuleCatalog、IDialogService、IModuleManager、IRegionManager、IEventAggregator、IRegionBehaviorFactory、IRegionNavigationJournalEntry、IRegionNavigationJournal
-
继承实现
IDialogWindow、IDialogAware、IActiveAware、INavigationAware、IConfirmNavigationRequest、IRegionMemberLifetime、IJournalAware、IModule
五、Caliburn.Micro框架
1. 关于
官网:
A small, yet powerful framework, designed for building applications across all XAML platforms. Its strong support for MVVM patterns will enable you to build your solution quickly, without the need to sacrifice code quality or testability.
于创建各类型的XAML平台应用的精简而又强大的框架。强力支持MVVM类的模式,使你的项目更快的建立,并且不牺牲代码质量以及可测试性。
官网:https://caliburnmicro.com
2. 框架基本使用
-
包引用:Nuget
- 入口改造:BooterStrapperBase、Bootstrapper
- MainViewModel => MainView
- 入口改造:BooterStrapperBase、Bootstrapper
-
通知属性与命令
- 基本绑定:属性绑定(PropertyChangedBase)、命令(是否可执行)
-
命令:事件-》命令
- 短语法
- 特殊参数:$eventArgs …….
3. 辅助对象
-
窗口管理器:IWindowManager
ShowDialogAsync
ShowWindowAsync
ShowPopupAsync
-
事件聚合器:IEventAggregator/Ihandle 用来做消息传递
弹窗:ViewModel 中不能直接操作View层的实例 new SubWindow()
4. 特色功能
-
Screen / Conductor<T>
-
向ViewModel提供相应的生命周期函数
-
实现:
- IResult
- 协同任务组件,
- INavigationService:导航Page FrameAdapter-》Frame
-
小案例:**页面呈现:单页、**Tab多页
-
自定义View匹配:ViewLocator
六、MVVM框架对比
| 框架名称 | MvvmLigth | CommunityToolkit.Mvvm | Prism | Caliburn.Micro | | ------------- | ---------------------------- | ---------------------------- | ---------------- | ---------------------------- | | 通知属性 | ObservableObject | ObservableObject | BindableBase | PropertyChangedBase | | ViewModel基类 | ViewModelBase | 无 | 无 | Screen/Conductor | | 命令对象 | RelayCommand | RelayCommand | DelegateCommand | Action自动匹配 | | 事件 | Behavior | Behavior | Behavior | Action自动匹配 | | 消息/事件总线 | Messenger | WeakReferenceMessenger | IEventArgureater | IEventArgureater | | 弹窗/窗口管理 | 无 | 无 | IDialogService | IWindowManager | | 默认IoC | SimpleIoc | 无 建议:IServiceCollection | Unity/DryIoc | SimpleContainer | | 区域化 | 无 | 无 | RegionManager | 无 | | 导航 | INavigationService 针对Page | 无 | RegionManager | INavigationService 针对Page | | 模块化 | 无 | 无 | Module | 无 | | 匹配规则 | 无 | 无 | 有 | 有 |