首页 > 编程语言 >[WPF] 使用 MVVM Toolkit 构建 MVVM 程序(CommunityToolkit.Mvvm)

[WPF] 使用 MVVM Toolkit 构建 MVVM 程序(CommunityToolkit.Mvvm)

时间:2023-12-23 22:13:41浏览次数:29  
标签:CommunityToolkit MVVM Mvvm ObservableObject Toolkit UI message public

1. 什么是 MVVM Toolkit

模型-视图-视图模型 (MVVM) 是用于解耦 UI 代码和非 UI 代码的 UI 体系结构设计模式。 借助 MVVM,可以在 XAML 中以声明方式定义 UI,并使用数据绑定标记将 UI 链接到包含数据和命令的其他层。

微软虽然提出了 MVVM,但又没有提供一个官方的 MVVM 库(多年前有过 Prism,但已经离家出走了)。每次有人提起 MVVM 库,有些人会推荐 Prism(例如我),有些人会推荐 MVVMLight。可是现在 Prism 已经决定不再支持 UWP , 而 MVVMLight 又不再更新,在这左右为难的时候 Windows Community Toolkit 挺身而出发布了 MVVM Toolkit。 MVVM Toolkit 延续了 MVVMLight 的风格,是一个轻量级的组件,而且它基于 .NET Standard 2.0,可用于UWP, WinForms, WPF, Xamarin, Uno 等多个平台。相比它的前身 MVVMLight,它有以下特点:

  • 更高:版本号更高,一出手就是 7.0。
  • 更快:速度更快,MVVM Toolkit 从一开始就以高性能为实现目标。
  • 更强:后台更强,MVVM Toolkit 的全称是 'Microsoft.Toolkit.Mvvm',根正苗红。

目前,MVVM Toolkit 已经更新到 '7.0.2',它的详细资料可以参考下面链接:

Nuget:https://www.nuget.org/packages/Microsoft.Toolkit.Mvvm 文档:https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/introduction 源码:https://github.com/CommunityToolkit/WindowsCommunityToolkit/tree/main/Microsoft.Toolkit.Mvvm

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

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

这篇文章将简单介绍 MVVM Toolkit 的几个基本组件。

2. 各个组件

2.1 ObservableObject

ObservableObject 实现了 INotifyPropertyChanged 和INotifyPropertyChanging,并触发 PropertyChanged 和 PropertyChanging 事件。

public class User : ObservableObject
{
    private string name;

    public string Name
    {
        get => name;
        set => SetProperty(ref name, value);
    }
}

在这段示例代码中,如果 name 和 value 的值不同,首先触发 PropertyChanging 事件,然后触发 PropertyChanged

2.2 RelayCommand

RelayCommand 和 RelayCommand<T> 实现了 ICommand 接口,INotifyPropertyChanged 和 ICommand 是 MVVM 模式的基础。下面的代码使用 ObservableObject 和 RelayCommand 展示一个基本的 ViewModel:

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++;
}
<Page
    x:Class="MyApp.Views.MyPage"
    xmlns:viewModels="using:MyApp.ViewModels">
    <Page.DataContext>
        <viewModels:MyViewModel x:Name="ViewModel"/>
    </Page.DataContext>

    <StackPanel Spacing="8">
        <TextBlock Text="{x:Bind ViewModel.Counter, Mode=OneWay}"/>
        <Button
            Content="Click me!"
            Command="{x:Bind ViewModel.IncrementCounterCommand}"/>
    </StackPanel>
</Page>

在这段示例里 IncrementCounterCommand 包装了 IncrementCounter 函数提供给 Button 绑定。IncrementCounter 函数更改 Counter 的值并通过 PropertyChanged 事件通知绑定的 TextBlock。

2.3 AsyncRelayCommand

AsyncRelayCommand 和 AsyncRelayCommand<T> 也实现了 ICommand,不过它们支持异步操作,提供的 ExecutionTask 和 IsRunning 两个属性对监视任务运行状态十分有用。

例如这个 ViewModel:

public MyViewModel()
{
    DownloadTextCommand = new AsyncRelayCommand(DownloadTextAsync);
}

public IAsyncRelayCommand DownloadTextCommand { get; }

private async Task<string> DownloadTextAsync()
{
    await Task.Delay(3000); // Simulate a web request

    return "Hello world!";
}

使用相关的 UI 代码:

<Page.Resources>
    <converters:TaskResultConverter x:Key="TaskResultConverter"/>
</Page.Resources>
<StackPanel Spacing="8">
    <TextBlock>
        <Run Text="Task status:"/>
        <Run Text="{x:Bind ViewModel.DownloadTextCommand.ExecutionTask.Status, Mode=OneWay}"/>
        <LineBreak/>
        <Run Text="Result:"/>
        <Run Text="{x:Bind ViewModel.DownloadTextCommand.ExecutionTask, Converter={StaticResource TaskResultConverter}, Mode=OneWay}"/>
    </TextBlock>
    <Button
        Content="Click me!"
        Command="{x:Bind ViewModel.DownloadTextCommand}"/>
    <muxc:ProgressRing
        HorizontalAlignment="Left"
        IsActive="{x:Bind ViewModel.DownloadTextCommand.IsRunning, Mode=OneWay}"/>
</StackPanel>

点击 Button 后 DownloadTextAsync 开始运行,在 UI 上 TextBlock 和 ProgressRing 绑定到 ExecutionTask 和 IsRunning 并显示任务运行状态,最后通过 TaskResultConverter 显示任务结果。

 

动图封面  

 

2.4 Messenger

对于主要目的是松耦合的 MVVM 框架,提供一个用于消息交换的系统十分有必要。MVVM Toolkit 中用于消息交换的核心是 WeakReferenceMessenger 类。

// Create a message
public class LoggedInUserChangedMessage : ValueChangedMessage<User>
{
    public LoggedInUserChangedMessage(User user) : base(user)
    {        
    }
}

// Register a message in some module
WeakReferenceMessenger.Default.Register<LoggedInUserChangedMessage>(this, (r, m) =>
{
    // Handle the message here, with r being the recipient and m being the
    // input messenger. Using the recipient passed as input makes it so that
    // the lambda expression doesn't capture "this", improving performance.
});

// Send a message from some other module
WeakReferenceMessenger.Default.Send(new LoggedInUserChangedMessage(user));

正如这段代码所示,WeakReferenceMessenger 主要通过 Register 和 Send 进行信息交换,它的使用方式类似于 MVVMLight 的 messenger 类。MVVM Toolkit 另外还提供了一个 StrongReferenceMessenger 类,更多使用方法可以参考这篇 文档Messenger 功能强大且简单易用,但也由于误用会带来风险而引发了一些争议,有必要更详细地理解它的原理和用法以避免它带来的其它风险,这篇文章只是简单地介绍一下它的用法。

2.5 ObservableRecipient

ObservableRecipient 继承了 ObservableObject 并支持从 Messenger 接收信息,可通过 IsActive 属性激活或停用。它可以用作 ViewModel 的基类,事实上它的作用基本上相遇于 MVVMLight 中的 ViewModelBase :

public class MyViewModel : ObservableRecipient, IRecipient<LoggedInUserRequestMessage>
{
    public void Receive(LoggedInUserRequestMessage message)
    {
        // Handle the message here
    }
}

3. The 性能

 

 

MVVM Toolkit 在开发过程中为了追求卓越的性能做了很多努力,例如提供一个 StrongReferenceMessenger 类,性能如上图所示地有了大幅提升。又例如下面这篇文章所介绍的:

MVVM Toolkit Preview 3 & The Journey of an API

有兴趣的话可以通过源码详细了解一下。

4. 结语

这篇文章简单介绍了 MVVM Toolkit 中的主要功能,更多内容可参考 源码单元测试 或 windows-toolkit/MVVM-Samples 中提供的示例应用:

 

 

标签:CommunityToolkit,MVVM,Mvvm,ObservableObject,Toolkit,UI,message,public
From: https://www.cnblogs.com/chinasoft/p/17923724.html

相关文章

  • WPF+SqlSugar+MVVM实现增删改查
    1、新建一个WPF应用(NETFramework)2、安装SqlSugarNuGet包3、在SqlSugar4.x下载代码生成器https://www.donet5.com/Doc/8/11374、在WPF中新建三个文件夹Models主要放实体类、Views主要放窗体、ViewModels主要是View逻辑的实现5、把生成的实体类放到Models文件夹内,在V......
  • CommunityToolkit.Mvvm 之 通过一个属性控制一个按钮是否禁用 及 按钮执行费时需任务
    要达到的目的:通过一个属性控制一个按钮是否禁用当按钮执行费时需任务时,按下禁用按钮,任务完成后自动解除禁用1. 属性定义1[ObservableProperty]2[NotifyCanExecuteChangedFor(nameof(SettingParamCommand))]//属性变化时通知对应的命令3privateboolallowOperator;2.......
  • .NET Core 3 WPF MVVM框架 Prism系列之导航系统
    本文将介绍如何在.NETCore3环境下使用MVVM框架Prism基于区域Region的导航系统git在讲解Prism导航系统以前,咱们先来看看一个例子,我在以前的demo项目建立一个登陆界面:github 咱们看到这里是否是一开始想象到使用WPF带有的导航系统,经过Frame和Page进行页面跳转,而后经过导航日志......
  • 08 MVVM框架
    08MVVM框架WPF是WindowsPresentationFoundation的缩写,它是一种用于创建桌面应用程序的用户界面框架。WPF支持多种开发模式,其中一种叫做MVVM(Model-View-ViewModel)。在WPF开发中,经典的编程模式是MVVM,是为WPF量身定做的模式,该模式充分利用了WPF的数据绑定机制,最大限度地降低了Xa......
  • 进一步学习 CommunityToolkit.Mvvm
    1.属性绑定privatestringtitle;publicstringTitle{get;set;} 可用以下属性方式替换,生成器会自动生成;[ObservableProperty]privatestringtitle; 另一种情况:命令privateboolisEnabled;publicboolIsEnabled{......
  • 进一步学习 CommunityToolkit.Mvvm 之 Messenger
    一、带token1.订阅消息WeakReferenceMessenger.Default.Register<UserMessage,string>(this,"MyToken",(r,m)=>{});2.发送消息WeakReferenceMessenger.Default.Send(newUserMessage(value),"MyToken");二、某一种数据类型发送接收消息1.订阅消息V......
  • [转][C#][WPF]MVVM 下的 ComboBox 数据绑定效果
    参考:https://www.cnblogs.com/xpvincent/p/3848790.html参考:https://blog.csdn.net/zhudaokuan/article/details/109059333前端:<ComboBoxName="cmbBox"ItemsSource="{Bindinglist}"DisplayMemberPath="Code"SelectedValu......
  • 前端框架中 MVC 和 MVVM 两种设计方式的区别
    MVC和MVVM是两种常见的软件架构模式。它们都致力于提供清晰的组织结构和代码分离,让开发者能够更有效率地开发和维护复杂的应用程序。然而,它们在组织代码和处理用户交互上有一些重要的区别。首先,让我们了解一下MVC(Model-View-Controller)模式。MVC是一种设计模式,被广泛应用于......
  • Wpf 第三方Mvvm包(mvvmLight/Microsoft.Toolkit.Mvvm/CommunityToolkit.Mvvm)
    十年河东,十年河西,莫欺少年穷学无止境,精益求精 mvvmLight和 Microsoft.Toolkit.Mvvm已被Nuget弃用且不再更新,在此不作说明CommunityToolkit.Mvvm是NetCore版本引用包,详情参考:WPFMVVM框架:CommunityToolkit.Mvvm包使用介绍1、wpf项目中使用 CommunityToolkit.Mvvm(NetCore3.1......
  • As a project I always want to create for myself as a gift, the MVVM framework is
    IusedtowanttobuildaMVVMprojectformyself,especiallysinceIwrotemymementowriterprojectwhichisnojQuery,andthatwasverytimeconsumingandtiringtocreate.Lastyear,Ihadsomeinspiration,andreallywantedtotrytostartfreshthin......