【WPF】Mvvm框架Toolkit.Mvvm 、MvvmLight、Prism8.0比较

  • Home
  • 卡牌图鉴
  • 【WPF】Mvvm框架Toolkit.Mvvm 、MvvmLight、Prism8.0比较

前言

本文基于.NET 6+VS2022+WPF。

在Wpf下最常使用的就是Mvvm模式了,有自己造轮子构建Mvvm框架的,也有使用现成的开源项目,我之前一直使用的是轻量级的MvvmLight了,这个框架还是非常不错的,使用也简单,不占用太大空间,其中最喜欢的莫过于全局Messenger了,可谓是神器。最近有个项目使用.Net6开发,在NuGet发现MvvmLight已经很久不更新了,上一次还是2018年9月12日,偶然发现微软官方出的Microsoft.Toolkit.Mvvm 完全继承了Messenger的优良传统,这是一个官方社区套件(Windows Community Toolkit),延续了MVVMLight的风格,是一个轻量级的组件,而且它基于.NET Standard 2.0,可用于UWP, WinForms, WPF, Xamarin, Uno等多个平台。Microsoft.Toolkit.Mvvm也已经过时了。现在微软推出全新的Mvvm框架=》CommunityToolkit.MVVM链接: https://docs.microsoft.com/zh-cn/windows/communitytoolkit/mvvm/introduction 机器翻译的有问题,不容易理解

个人的:https://blog.csdn.net/BadAyase/article/details/125112080 容易理解

备注

我发现这个术语在WPF和Silverl社区更为流行。与MVP中的Presenter不同,ViewModel不需要实现对View的引用。View将属性绑定到ViewModel中,反向的,ViewModel暴露的属性包含在Model对象和View中特殊的状态。View和ViewModel之间的绑定的构建非常简单只需将ViewModel对象被作为View的上下文(DataContext)来设置。

MVVM Toolkit版本

自定义Mvvm框架:方便自己理解mvvm框架。

MvvmLight:已经过时,被Microsoft.Toolkit.Mvvm取代。在NuGet发现MvvmLight已经很久不更新了,上一次还是2018年9月12日。

Microsoft.Toolkit.Mvvm:已经过时,停止更新。一发布就是版本7。两大特性RelayCommand和Messenger。延续了MVVMLight的风格,是一个轻量级的组件,而且它基于.NET Standard 2.0,可用于UWP, WinForms, WPF, Xamarin, Uno等多个平台。将要过 时,将被CommunityToolkit.Mvvm取代。

Nuget:https://www.nuget.org/packages/Microsoft.Toolkit.Mvvm

文档:https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/introduction

源码:https://github.com/MartinZikmund/Uno.WindowsCommunityToolkit/blob/uno/Microsoft.Toolkit.Mvvm/Input/RelayCommand.cs

虽然是 Windows Community Toolkit 项目的一部分,但它有独立的 Sample 和文档,可以在这里找到:

https://github.com/CommunityToolkit/MVVM-Samples

CommunityToolkit.Mvvm:目前使用中,一发布就是版本8。两大特性RelayCommand和Messenger。延续了MVVMLight的风格。所有可用的 API 都不依赖于任何特定的运行时或框架,因此所有 .NET 开发人员都可以使用它们。这些库是从 .NET Standard 2.0 到 .NET 6 的多目标库,所以它们既可以支持尽可能多的平台,又可以在与较新的运行时一起使用时进行优化以获得最佳性能。主要应该代码生成器的功能简化代码(CommunityToolkit工具包提供了一系列可重用实现,旨在简化各种 .NET 框架的常见开发任务。),应用大量的特性来简化代码编写。详细请查看

Nuget: https://www.nuget.org/packages/CommunityToolkit.Mvvm源码:https://github.com/CommunityToolkit/MVVM-Samples

Prism8.0:应用与大型的应用程序

Toolkit.Mvvm工具包简介

未来方便理解mvvm的原理这里主要介绍Microsoft.Toolkit.Mvvm,虽然他已经过时了。CommunityToolkit.Mvvm 详细请查看。

1、ObservableObject的使用在MvvmLight框架下,只要在ViewModel继承ViewModelBase即可,在Microsoft.Toolkit.Mvvm中正常继承ObservableObject即可,同时还有ObservableRecipient、ObservableValidator等可被选择,其实在MvvmLight框架下,ViewModelBase也是继承了ObservableObject,相当于官方的这个框架更加的灵活,在不同的场景下继承不同的类,以实现不同的效果,这也跟.Net Core很像,一切都更加原子化,模块化。ObservableObject:实现了最基本的属性更新:SetProperty 等ObservableRecipient:继承自ObservableObject,增加了Messenger的相关功能ObservableValidator:这个就更不用说了,看名字就知道是用于验证属性的

public class MainWindowViewModel : ObservableObject

{

public MainWindowViewModel()

{

Status = "Hello";

}

private string _status;

public string Status

{

get => _status;

set => SetProperty(ref _status, value);

}

}

前端绑定属性就行了

2、IRelayCommand和IAsyncRelayCommand

RelayCommand 和 RelayCommand:唯一的作用就是充当view 和viewmodel方法之间连接器。

AsyncRelayCommand 和 AsyncRelayCommand

RelayCommand 和 RelayCommand 工作原理

RelayCommand和RelayCommand的主要特性如下:它们提供了ICommand接口的基本实现。它们还实现了IRelayCommand(和IRelayCommand)接口,该接口公开了一个NotifyCanExecuteChanged方法来引发CanExecuteChanged事件。它们公开了接受Action和Func等委托的构造函数,这些委托允许包装标准方法和lambda表达式。

应用一 、同步应用

ViewModel.cs

public class MyViewModel : ObservableObject

{

public MyViewModel()

{

IncrementCounterCommand = new RelayCommand(IncrementCounter);

}

private int counter;

public int Counter

{

get => counter;

private set => SetProperty(ref counter, value);

}

public ICommand IncrementCounterCommand { get; }

private void IncrementCounter() => Counter++;

}

x:Class="MyApp.Views.MyPage"

xmlns:viewModels="using:MyApp.ViewModels">

Content="Click me!"

Command="{x:Bind ViewModel.IncrementCounterCommand}"/>

应用二、异步应用

要实现按钮的点击事件进行绑定,都需要使用继承自ICommand的接口,IRelayCommand和IAsyncRelayCommand也是如此,同时增加了NotifyCanExecuteChanged来通知ICommand.CanExecute属性发生了改变。这里以IAsyncRelayCommand为例来实现一个进度条的功能,

public class MainWindowViewModel : ObservableObject

{

public MainWindowViewModel()

{

Status = "Hello";

ExecCommand = new AsyncRelayCommand(ExecAsync);

}

private string _status;

public string Status

{

get => _status;

set => SetProperty(ref _status, value);

}

private int _progressValue;

public int ProgressValue

{

get => _progressValue;

set => SetProperty(ref _progressValue, value);

}

public ICommand ExecCommand { get; }

private async Task ExecAsync()

{

Status = "Processing...";

await Task.Run(async () =>

{

for (int i = 0; i <= 100; i++)

{

ProgressValue = i;

await Task.Delay(100);

}

});

Status = "Complete";

}

}

前端如下