什么是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
dotnet add package Microsoft.Toolkit.Mvvm
官方指導文檔
https://docs.microsoft.com/zh-cn/windows/communitytoolkit/mvvm/introduction
using Microsoft.Toolkit.Mvvm;
官方指導示例
項目源碼倉庫
開發探索指引
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
}
}