1. 程式人生 > 其它 >乘風破浪,遇見MVVM Toolkit官方社群首推MVVM框架,後UWP時代的拯救版MVVM框架

乘風破浪,遇見MVVM Toolkit官方社群首推MVVM框架,後UWP時代的拯救版MVVM框架

什麼是MVVM Toolkit

大家一說起WPF或者UWP能用的MVVM框架,肯定主流的推薦就是Prism和MVVMLight這兩個,算是使用最廣泛的,但是目前Prism已經不再支援UWP了,然後MVVMLight已經多年不更新了,那就玩完了?

不,官方社群套件(Windows Community Toolkit)挺身而出,帶來了拯救版MVVM Toolkit這個MVVM框架

MVVM Toolkit延續了MVVMLight的風格,是一個輕量級的元件,而且它基於.NET Standard 2.0,可用於UWP, WinForms, WPF, Xamarin, Uno等多個平臺。

相比它的前身 MVVMLight,它有以下特點:

  • 更高:版本號更高,一出手就是7.0。
  • 更快:速度更快,MVVM Toolkit從一開始就以高效能為實現目標。
  • 更強:後臺更強,MVVM Toolkit的全程是'Microsoft.Toolkit.Mvvm',根正苗紅。

安裝MVVM Toolkit

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

dotnet add package Microsoft.Toolkit.Mvvm

官方指導文件

https://docs.microsoft.com/zh-cn/windows/communitytoolkit/mvvm/introduction

using Microsoft.Toolkit.Mvvm;

官方指導示例

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

專案原始碼倉庫

https://github.com/windows-toolkit/WindowsCommunityToolkit

開發探索指引

ObservableObject

public class User : ObservableObject
{
    private string name;

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

RelayCommand

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>

AsyncRelayCommand

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!";
}
<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>

Messenger

// 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));

ObservableRecipient

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

參考