在跨平台 UI 框架领域,Avalonia 凭借其与 WPF 兼容的 API 设计、多平台适配能力(支持 Windows、macOS、Linux 等)备受关注。而 ReactiveUI 作为基于响应式编程(Reactive Programming)的 MVVM 框架,能与 Avalonia 深度集成,不仅简化了数据绑定、事件处理和命令调用的逻辑,更从根源上减少了内存泄露风险。本文将通过一个完整的 “色彩展示与导航” 示例,详细讲解 Avalonia 中如何利用 ReactiveUI 实现响应式开发,涵盖 ViewModel 设计、View 绑定、命令与事件关联、样式配置等核心环节。
一、核心技术与优势概述
在开始实践前,先明确本次示例涉及的核心技术及优势,帮助读者建立整体认知:
| 技术组件 | 核心作用 | 关键优势 |
|---|---|---|
| Avalonia | 跨平台 UI 框架 | 与 WPF 语法兼容,无需重写代码即可实现多平台部署;支持自定义控件与灵活样式 |
| ReactiveUI | 响应式 MVVM 框架 | 基于 Rx.NET,通过 “数据流” 实现 View 与 ViewModel 联动;自动管理绑定生命周期,预防内存泄露 |
| Splat | 依赖注入容器 | 轻量级 DI 工具,简化 ViewModel 实例的创建与管理,降低组件耦合 |
| FuncValueConverter | 数据转换器 | 便捷实现数据格式转换(如 Color 转 Hex/CMYK 色值),无需单独定义转换器类 |
二、完整实现步骤
本示例将构建一个包含 “色彩展示” 和 “关于” 两个页面的应用,支持页面切换、色彩信息(名称、Hex 码、CMYK 值)展示,所有交互逻辑基于 ReactiveUI 实现。
1. 项目初始化与依赖配置
首先创建 Avalonia 项目(选择 “MVVM Application” 模板),并通过 NuGet 安装以下核心依赖:
Avalonia.ReactiveUI:Avalonia 与 ReactiveUI 的集成包ReactiveUI:ReactiveUI 核心库ReactiveUI.SourceGenerators:通过源代码生成器简化 Reactive 属性与命令的定义Splat:依赖注入容器
2. 定义 ViewModel(业务逻辑层)
ViewModel 是 MVVM 模式的核心,负责封装业务逻辑与数据,通过 ReactiveUI 提供的特性实现 “响应式” 能力。本次示例需创建 3 个 ViewModel:ColorsViewModel(色彩数据处理)、AboutViewModel(关于页面数据)、MainWindowViewModel(主窗口导航逻辑)。
2.1 ColorsViewModel:色彩数据与转换逻辑
该 ViewModel 负责加载系统颜色、定义颜色格式转换器(Hex/CMYK),并通过 ReactiveCommand 触发初始化逻辑。
using Avalonia.Data.Converters;
using Avalonia.Media;
using ReactiveUI.SourceGenerators;
using System;
using System.Collections.ObjectModel;
using System.Reflection;
namespace ReactiveUIDemo.ViewModels
{
// 继承 ViewModelBase(ReactiveUI 提供,实现 INotifyPropertyChanged)
public partial class ColorsViewModel : ViewModelBase
{
// [Reactive] 特性:自动生成支持属性变更通知的代码(替代 INotifyPropertyChanged 手动实现)
[Reactive]
private string? _colorName; // 颜色名称
[Reactive]
private Color? _color; // 颜色对象
// 存储所有颜色数据的集合(ObservableCollection 支持集合变更通知)
public readonly ObservableCollection<ColorsViewModel> Colors = [];
// 构造函数:初始化时暂不加载数据,通过命令触发
public ColorsViewModel() { }
// [ReactiveCommand] 特性:自动生成命令(替代 ICommand 手动实现)
[ReactiveCommand]
private void Init()
{
// 反射获取 System.Windows.Media.Colors 类的所有静态颜色属性
var colorProperties = typeof(Colors).GetProperties(
BindingFlags.Static | BindingFlags.Public);
foreach (var property in colorProperties)
{
// 筛选出类型为 Color 的属性
if (property.GetValue(null) is Color color)
{
Colors.Add(new ColorsViewModel
{
ColorName = property.Name, // 颜色名称(如 AliceBlue)
Color = color // 颜色对象
});
}
}
}
// 颜色转 Hex 格式转换器(静态属性,供 XAML 直接引用)
public static FuncValueConverter<Color, string> ToHex { get; } =
new FuncValueConverter<Color, string>(color =>
$"#{color.R:X2}{color.G:X2}{color.B:X2}"); // R/G/B 转两位十六进制
// 颜色转 CMYK 格式转换器(基于 RGB 与 CMYK 换算公式)
public static FuncValueConverter<Color, string> ToCMYK { get; } =
new FuncValueConverter<Color, string>(color =>
{
// RGB 取值归一化(转为 0-1 之间的小数)
double r = color.R / 255.0;
double g = color.G / 255.0;
double b = color.B / 255.0;
// 计算 K 值(黑色分量)
double k = 1 - Math.Max(Math.Max(r, g), b);
// 计算 C/M/Y 分量(若 K=1,C/M/Y 均为 0)
double c = k < 1 ? (1 - r - k) / (1 - k) : 0;
double m = k < 1 ? (1 - g - k) / (1 - k) : 0;
double y = k < 1 ? (1 - b - k) / (1 - k) : 0;
// 格式化输出(保留 1 位小数)
return $"C={Math.Round(c * 100, 1)}% M={Math.Round(m * 100, 1)}% Y={Math.Round(y * 100, 1)}% K={Math.Round(k * 100, 1)}%";
});
}
}
2.2 AboutViewModel:关于页面数据
封装应用名称、版本号等静态信息,通过反射自动获取程序集信息。
using ReactiveUI.SourceGenerators;
using System.Reflection;
namespace ReactiveUIDemo.ViewModels
{
public partial class AboutViewModel : ViewModelBase
{
[Reactive]
private string? _appName; // 应用名称
[Reactive]
private string? _version; // 应用版本
// 静态描述信息(无需变更通知,直接定义为只读属性)
public string Message => "这是采用

最低0.47元/天 解锁文章
2472

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



