• [WPF] 使用 MVVM Toolkit 构建 MVVM 程序


    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 事件。

    Copy
    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:

    Copy
    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++;
    }
    
    Copy
    <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:

    Copy
    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 代码:

    Copy
    <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 类。

    Copy
    // 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 :

    Copy
    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 中提供的示例应用:

    5. 参考#

    Sample repo for MVVM package

    Microsoft.Toolkit.Mvvm at master

    [Feature] Basic MVVM primitives (.NET Standard)

    NuGet Gallery _ Microsoft.Toolkit.Mvvm

    MVVM Light Toolkit

    数据绑定和 MVVM

    [Feature] Microsoft.Toolkit.Mvvm package (Preview 5)

    MVVM Toolkit Preview 3 & The Journey of an API

  • 相关阅读:
    【Jmeter】他人总结篇链接(共八篇相关文章)
    基于web站点的xss攻击
    【雅思】【绿宝书错词本】List37~48
    【雅思】【绿宝书错词本】List25~36
    【雅思】【绿宝书错词本】List13~24
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
    jQuery火箭图标返回顶部代码
  • 原文地址:https://www.cnblogs.com/siyunianhua/p/15166837.html
Copyright © 2020-2023  润新知