总目录
前言
前面的几章为我们筑好了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接口
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name=null)
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(name));
}
public void Set<T>(ref T field, object value, [CallerMemberName] string name="")
{
field= (T?)value!;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
2.实现ICommand接口以及事件转命令
- 实现实现ICommand接口
public class DelegateCommand : ICommand
{
public event EventHandler? CanExecuteChanged;
public DelegateCommand(Action executeActionNoPara, Func<bool> canExcuteFuncNoPara = null!)
{
this.ExecuteActionNoPara = executeActionNoPara;
this.CanExcuteFuncNoPara = canExcuteFuncNoPara;
}
public DelegateCommand(Action<object?> executeAction, Func<object?, bool> canExcuteFunc = null!)
{
this.ExecuteAction= executeAction;
this.CanExcuteFunc = canExcuteFunc;
}
public bool CanExecute(object? parameter=null)
{
if (parameter==null) return this.CanExcuteFuncNoPara == null ? true : this.CanExcuteFuncNoPara.Invoke();
return this.CanExcuteFunc == null ? true : this.CanExcuteFunc.Invoke(parameter);
}
public void Execute(object? parameter = null)
{
if (parameter == null) this.ExecuteActionNoPara?.Invoke();
else this.ExecuteAction?.Invoke(parameter);
}
public Action ExecuteActionNoPara { get; set; }
public Func<bool> CanExcuteFuncNoPara { get; set; }
public Action<object?> ExecuteAction { get; set; }
public Func<object?,bool> CanExcuteFunc { get; set; }
}
- 事件转命令
-
- 1 首先添加名为
Microsoft.Xaml.Behaviors.Wpf
的NuGet包
- 1 首先添加名为
-
- 2 然后在界面中引用 xmlns:i=“http://schemas.microsoft.com/xaml/behaviors”
-
- 3 使用,具体使用方法如下:
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Background="Red">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding MouseDownCommand}"></i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
3.实现窗体间的交互与数据传递
这一块儿的内容,当前系列之前并没有介绍,在这里介绍一下。
假如现在有这样一个需求,点击用户列表中的某一项,我需要打开一个窗口查看该项的详情页,那么必定就会涉及,新开一个窗口,并且窗体将需要传递数据。
如果我们在ViewModel 中按照下面代码实现:
private void ShowDetail()
{
UserDetailView view = new UserDetailView();
//.....
UserDetailView.Show();
}
功能是可以实现,但是显然,不符合解耦的目的。MVVM的目的就是解耦,如果在ViewModel中操作View的内容,无疑又干回去!那我们应该去如何操作呢?定义一个专用于窗体间交互与数据传递的类,
窗体间需要做任何事情,都找"它"。
形如:
public class WindowManager
{
private static Dictionary<string, Action<object>> _dir = new Dictionary<string, Action<object>>();
public static void Register(string key,Action<object> action)
{
if (!string.IsNullOrEmpty(key)&&!_dir.ContainsKey(key))
{
_dir.Add(key,action);
}
}
public static void DoAction(string key,object obj)
{
if (!string.IsNullOrEmpty(key) && _dir.ContainsKey(key))
{
_dir[key]?.Invoke(obj);
}
}
}
当然,我们还可以根据项目对该类做完善和扩展。
4.页面切换时数据的处理
未完待续文章来源:https://www.toymoban.com/news/detail-426073.html
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用于两者的解耦。
结语
以上就是本文要介绍的内容,希望以上内容可以帮助到你,如文中有不对之处,还请批评指正。文章来源地址https://www.toymoban.com/news/detail-426073.html
到了这里,关于第六章:自建MVVM模式的简易项目框架的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!