在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
<Window
x: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。
Avalonia中异步命令实现
1298

被折叠的 条评论
为什么被折叠?



