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 Avalonia.Controls;
using AvaRea.Models;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using System;
using System.Collections.ObjectModel;
namespace AvaRea.ViewModels
{
public partial class TestTodoViewModel: ReactiveObject
{
public TestTodoViewModel()
{
// 设计模式下显示待办事项内容.
if (Design.IsDesignMode)
{
ToDoItems = new ObservableCollection<ToDoItem>(new[]
{
new ToDoItem() { Content = "学习RT-Thread嵌入式操作系统" },
new ToDoItem() { Content = "学习Avalonia及响应式编程", IsChecked = true}
});
}
// 响应式编程模式,自动判断初始化待办事项列表是否为空且是使能新增待办实现命令.
_canAddItem = this.WhenAnyValue(x => x.NewItemContent,(x) => !string.IsNullOrWhiteSpace(x));
}
/// <summary>
/// 界面中显示的待办事项列表
/// </summary>
public ObservableCollection<ToDoItem> ToDoItems { get; } = new ObservableCollection<ToDoItem>();
/// <summary>
/// 新增待办事项的命令,当输入内容不为空时,命令可用
/// </summary>
[ReactiveCommand(CanExecute = nameof(_canAddItem))]
private void AddItem()
{
// 在待办事项列表中添加一个新的待办事项
ToDoItems.Add(new ToDoItem() { Content = NewItemContent });
// 复位输入框内容NewItemContent
NewItemContent = null;
}
/// <summary>
/// 输入框内容,当输入内容不为空时,命令可用
/// </summary>
[Reactive]
private string? _newItemContent;
/// <summary>
/// 响应式编程模式检查输入框内容,当输入内容不为空时,新增待办事项命令可用
/// </summary>
private IObservable<bool> _canAddItem;
/// <summary>
/// 移除待办事项内容
/// </summary>
/// <param name="item"></param>
[ReactiveCommand]
private void RemoveItem(ToDoItem item)
{
// 在待办事项列表中移除指定的待办事项
ToDoItems.Remove(item);
}
}
}
2、Model
using ReactiveUI;
using ReactiveUI.SourceGenerators;
namespace AvaRea.Models
{
/// <summary>
/// 待办事项模型类
/// </summary>
public partial class ToDoItem : ReactiveObject
{
/// <summary>
/// 获取/设置待办事项是否已完成
/// </summary>
[Reactive] private bool _isChecked;
/// <summary>
/// 获取/设置待办事项内容
/// </summary>
[Reactive] string? _content;
}
}
3、View
<Window
x:Class="AvaRea.TestTodoView"
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="using:AvaRea.ViewModels"
Title="待办事项"
d:DesignHeight="450"
d:DesignWidth="800"
x:DataType="vm:TestTodoViewModel"
mc:Ignorable="d">
<Design.DataContext>
<vm:TestTodoViewModel />
</Design.DataContext>
<Grid x:Name="Root" RowDefinitions="Auto, *, Auto">
<TextBlock Classes="h1" Text="我的待办事项" />
<ScrollViewer Grid.Row="1">
<!-- ItemsControl显示所有待办事项 -->
<ItemsControl ItemsSource="{Binding ToDoItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="*, Auto">
<CheckBox Content="{Binding Content}" IsChecked="{Binding IsChecked}" />
<Button
Grid.Column="1"
Command="{Binding #Root.((vm:TestTodoViewModel)DataContext).RemoveItemCommand}"
CommandParameter="{Binding .}"
Content="删除"
Foreground="Red" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<TextBox
Grid.Row="2"
Text="{Binding NewItemContent}"
Watermark="新增待办事项">
<TextBox.InnerRightContent>
<Button Command="{Binding AddItemCommand}">
<TextBlock Foreground="Green" Text="新增" />
</Button>
</TextBox.InnerRightContent>
<TextBox.KeyBindings>
<KeyBinding Command="{Binding AddItemCommand}" Gesture="Enter" />
</TextBox.KeyBindings>
</TextBox>
</Grid>
</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 TestTodoView
{
DataContext = new TestTodoViewModel()
};
}
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
{
singleViewPlatform.MainView = new TestTodoView
{
DataContext = new TestTodoViewModel()
};
}
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、程序运行界面

8、主要特点
使用 _canAddItem属性并利用ReactiveUI响应式编程特点和Sourcegenerators简化代码的功能控制 UI 状态和命令可用性,无需在axaml代码中进行使能绑定。
总结
Avalonia 给你跨平台的舞台,ReactiveUI 给你响应式的灵魂,Source Generators 给你自动生成代码;三者合体 = 用最少的代码,写出最快、最稳、最易维护的跨平台 .NET UI。
1298

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



