Avalonia+ReactiveUI+SourceGenerators带返回值的异步命令实现
在Avalonia+ReactiveUI+SourceGenerators组合下设计带返回值的异步命令,在不阻塞主线程的情况下执行耗时较长的程序代码,待代码执行完毕后,返回并显示结果,设计一简单示例如下:
1、必要的包引用
<PackageReference Include="Avalonia" Version="11.3.6" /><PackageReference Include="Avalonia.ReactiveUI" Version="11.3.6" /><PackageReference Include="ReactiveUI.SourceGenerators" Version="2.4.1">
2、ViewModel (使用 ReactiveUI Source Generators)
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using System;
using System.Threading;
using System.Threading.Tasks;namespace AvaRea.ViewModels
{public partial class TestCmdViewModel: ReactiveObject{[ObservableAsProperty]private string _comResult;[ReactiveCommand]private async Task<string> ComDataAsync(){// 模拟耗时操作await Task.Delay(1000);// 模拟数据计算return $"数据计算完成: {3+4}";} public TestCmdViewModel(){// _comResultHelper是由ReactiveUI.SourceGenerators.ObservableAsPropertyGenerator生成的可观察属性_comResultHelper = ComDataCommand.ToProperty(this, x=>x.ComResult, scheduler: RxApp.MainThreadScheduler);}}
}
3、View
<Windowx:Class="AvaRea.TestCmdView"xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:vm="clr-namespace:AvaRea.ViewModels"Title="测试带返回值的异步命令"Width="300"Height="400"d:DesignHeight="400"d:DesignWidth="300"x:DataType="vm:TestCmdViewModel"mc:Ignorable="d"><StackPanel Margin="20" Spacing="10"> <Button Content="开始计算" Command="{Binding ComDataCommand}"/><TextBlock Text="{Binding ComResult}" Margin="0,10,0,0"/> </StackPanel>
</Window>
4、App.axaml
<Application xmlns="https://github.com/avaloniaui"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="AvaRea.App"RequestedThemeVariant="Default"><!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --><Application.Styles><FluentTheme /></Application.Styles>
</Application>
5、App.axaml.cs
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using AvaRea.ViewModels;namespace AvaRea;public partial class App : Application
{public override void Initialize(){AvaloniaXamlLoader.Load(this);}public override void OnFrameworkInitializationCompleted(){if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop){desktop.MainWindow = new TestCmdView{DataContext = new TestCmdViewModel()};}else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform){singleViewPlatform.MainView = new TestCmdView{DataContext = new TestCmdViewModel()};}base.OnFrameworkInitializationCompleted();}
}
6、Program.cs
using System;using Avalonia;
using Avalonia.ReactiveUI;namespace AvaRea.Desktop;class Program
{// Initialization code. Don't use any Avalonia, third-party APIs or any// SynchronizationContext-reliant code before AppMain is called: things aren't initialized// yet and stuff might break.[STAThread]public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);// Avalonia configuration, don't remove; also used by visual designer.public static AppBuilder BuildAvaloniaApp()=> AppBuilder.Configure<App>().UsePlatformDetect().WithInterFont().LogToTrace().UseReactiveUI();
}
7、主要特点
通过ReactiveUI.SourceGenerators.ObservableAsPropertyGenerator生成的可观察属性_comResultHelper获取命令的返回值,通过ToProperty方法转化为可绑定属性ComResult。
总结
Avalonia 给你跨平台的舞台,ReactiveUI 给你响应式的灵魂,Source Generators 为你自动生成代码,减少编写繁杂的样板代码烦恼;三者合体 = 用最少的代码,写出最快、最稳、最易维护的跨平台 .NET UI。
