总目录
文章目录
前言
前面的几章为我们筑好了MVVM的基础,在这一章中我们将自己搭建一个MVVM模式下的简易项目框架。
一、MVVM是什么?
1.介绍
MVVM是一种模式,主要目的是降低界面和业务逻辑的耦合。
MVVM是Model-View-ViewModel(模型-视图-视图模型)的简写。是WPF开发过程中必不可少的一种开发模式,MVVM基本结构如下图所示:
- View(视图) 就是交互界面,接受用户的输入和展示数据;
- Model(模型) 是数据模型,项目中的对象,包含属性和行为,项目中的任何事物都可抽象为Model,例如项目中一个用户,我们可以抽象为一个用户的类,可以包含该用户的姓名,出生日期,电话等等信息
- ViewModel(视图模型)是负责处理业务逻辑的核心。
- 三者关系:在View和ViewModel中通过数据绑定将界面上元素的依赖属性与实现了INotifyPropertyChanged的ViewModel中的属性进行绑定,实现数据的实时更新机制。在View和ViewModel中通过命令绑定将界面上的操作用Command属性与ViewModel中实现了ICommand的命令进行绑定,实现了用户操作指令的下发。而Model 则是负责给ViewModel提供View所需的对象的数据模型。
- 通过MVVM这种模式可以最大限度的降低UI界面,数据模型,逻辑业务之间的耦合。让View 将关注点优化呈现效果上,至于数据和操作只需绑定即可;让Model将关注点放在数据模型上,ViewModel将关注点放在处理核心业务逻辑上。
2.优势
- 低耦合,View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
- 提高代码重用,可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑;
- 独立开发,业务开发人员可以专注于业务逻辑和数据的开发,界面开发人员可以专注于页面的开发。
二、搭建MVVM项目框架
现在我们开始着手搭建MVVM项目框架,步骤如下:
(1)首先需要新建一个项目,创建Views,ViewModels,Models 三个文件夹,这样基本结构就搭建好了。
(2)将我们写的xaml页面放在Views目录下,一般就是命名为:xxxView,然后与之对应的视图模型命令为xxxViewModel放在ViewModels目录下,另外将需要的数据模型放置在Models目录下。
(3)再者需要创建一些辅助类的文件目录,一般会创建Resources用于存放一些资源如样式,字体,图片等等,创建一个Helper或者Common的目录,用于存放一些公用的方法类或者帮助类。
具体目录如下图所示:
这样一个简易的MVVM项目框架就搭建好了,当然在后面我们会接触到按照MVVM模式已搭建好的比较完善的框架供我们使用。
三、WPF中实现MVVM的重点内容
1.实现INotifyPropertyChanged接口
publicclassViewModelBase:INotifyPropertyChanged{publiceventPropertyChangedEventHandler? PropertyChanged;publicvoidOnPropertyChanged([CallerMemberName]string name=null){
PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(name));}publicvoidSet<T>(refT field,objectvalue,[CallerMemberName]string name=""){
field=(T?)value!;
PropertyChanged?.Invoke(this,newPropertyChangedEventArgs(name));}}
2.实现ICommand接口以及事件转命令
- 实现实现ICommand接口
publicclassDelegateCommand:ICommand{publiceventEventHandler? CanExecuteChanged;publicDelegateCommand(Action executeActionNoPara,Func<bool> canExcuteFuncNoPara =null!){this.ExecuteActionNoPara = executeActionNoPara;this.CanExcuteFuncNoPara = canExcuteFuncNoPara;}publicDelegateCommand(Action<object?> executeAction,Func<object?,bool> canExcuteFunc =null!){this.ExecuteAction= executeAction;this.CanExcuteFunc = canExcuteFunc;}publicboolCanExecute(object? parameter=null){if(parameter==null)returnthis.CanExcuteFuncNoPara ==null?true:this.CanExcuteFuncNoPara.Invoke();returnthis.CanExcuteFunc ==null?true:this.CanExcuteFunc.Invoke(parameter);}publicvoidExecute(object? parameter =null){if(parameter ==null)this.ExecuteActionNoPara?.Invoke();elsethis.ExecuteAction?.Invoke(parameter);}publicAction ExecuteActionNoPara {get;set;}publicFunc<bool> CanExcuteFuncNoPara {get;set;}publicAction<object?> ExecuteAction {get;set;}publicFunc<object?,bool> CanExcuteFunc {get;set;}}
- 事件转命令
- 1 首先添加名为
Microsoft.Xaml.Behaviors.Wpf
的NuGet包
- 1 首先添加名为
- 2 然后在界面中引用 xmlns:i=“http://schemas.microsoft.com/xaml/behaviors”
- 3 使用,具体使用方法如下:
<StackPanelVerticalAlignment="Center"HorizontalAlignment="Center"Background="Red"><i:Interaction.Triggers><i:EventTriggerEventName="MouseDown"><i:InvokeCommandActionCommand="{Binding MouseDownCommand}"></i:InvokeCommandAction></i:EventTrigger></i:Interaction.Triggers></StackPanel>
3.实现窗体间的交互与数据传递
这一块儿的内容,当前系列之前并没有介绍,在这里介绍一下。
假如现在有这样一个需求,点击用户列表中的某一项,我需要打开一个窗口查看该项的详情页,那么必定就会涉及,新开一个窗口,并且窗体将需要传递数据。
如果我们在ViewModel 中按照下面代码实现:
privatevoidShowDetail(){UserDetailView view =newUserDetailView();//.....
UserDetailView.Show();}
功能是可以实现,但是显然,不符合解耦的目的。MVVM的目的就是解耦,如果在ViewModel中操作View的内容,无疑又干回去!那我们应该去如何操作呢?定义一个专用于窗体间交互与数据传递的类,
窗体间需要做任何事情,都找"它"。
形如:
publicclassWindowManager{privatestaticDictionary<string, Action<object>> _dir =newDictionary<string, Action<object>>();publicstaticvoidRegister(string key,Action<object> action){if(!string.IsNullOrEmpty(key)&&!_dir.ContainsKey(key)){
_dir.Add(key,action);}}publicstaticvoidDoAction(string key,object obj){if(!string.IsNullOrEmpty(key)&& _dir.ContainsKey(key)){
_dir[key]?.Invoke(obj);}}}
当然,我们还可以根据项目对该类做完善和扩展。
4.页面切换时数据的处理
未完待续
5.特别说明
- View中依赖属性需要绑定ViewModel中的属性
- 注意绑定的是ViewModel中的属性,不是字段。
- 注意为了实现View和Model的隔离,View是绑定ViewModel中属性,而不可以直接绑定Model层,Model可以为ViewModel提供数据模型,如我们常见场景Model中有个UserInfo类,然后再在ViewModel将UserInfo 申明为一个属性User,View会绑定ViewModel中User属性
- 那么何时将属性设置在ViewModel中,何时将属性放在Model中供ViewModel使用呢? ①一般页面上展示集合的情况,都是需要将数据模型放在Model层,然后通过ViewModel申明为一个泛型集合来使用; ②在界面上有一些不同区域需要展示不同数据的情况,如,左边需要放用户数据,右边需要放订单数据或其他什么数据,就需要在Model中分别定义数据模型,然后ViewModel中使用; ③在少数情况下可以直接在属性申明在ViewModel中,而省去在Model中定义数据模型,这类情况一般就是该属性复用的地方极少,或者只有一两个零散的属性会在View中需要使用。
- 在绑定集合的时候,若要设置动态绑定,以便集合中的插入或删除操作可以自动更新 UI,则集合必须实现 INotifyCollectionChanged 接口,WPF 提供 ObservableCollection 类,该类是公开 INotifyCollectionChanged 接口的数据集合的内置实现。如果还要实现集合每项对象属性值的变化通知到UI则还需要集合的数据对象实现INotifyCollectionChanged。
- 解耦的根本在个人理解来看,就是加个"第三方代理商",有什么事情都找代理商,比如要将View和Model 解耦,就加了一个ViewModel用于两者的解耦。
结语
以上就是本文要介绍的内容,希望以上内容可以帮助到你,如文中有不对之处,还请批评指正。
版权归原作者 鲤籽鲲 所有, 如有侵权,请联系我们删除。