Files
AtomUI/docs/Core/ControlInfrastructure.md
chinboy 2a9620a3f9 docs(Core): add and update core subsystem documentation
- Add IconSystem, AnimationSystem, CollectionSystem documentation
- Add ControlInfrastructure, CoreTypesAndUtilities documentation
- Add DataBindingSystem, MediaAndDrawing documentation
- Update MotionScene docs (Architecture, BuiltinMotions, DeveloperGuide, Overview)
- Update commit-message-convention: Body section Optional → Recommended
2026-04-10 18:48:42 +08:00

8.1 KiB
Raw Permalink Blame History

控件基础设施(Control Infrastructure)

概述

控件基础设施位于 src/AtomUI.Core/ 的多个目录中(Controls/、Input/、Reactive/),为所有 AtomUI 控件提供了动效感知、坐标追踪、焦点导航、响应式编程等基础能力。这些不是具体的 UI 控件,而是控件开发的底层支撑框架。

在整体架构中的位置

具体 UI 控件(Button, Input, Select 等)
    ↓ 继承/实现
Control Infrastructure(本文档 — 接口、工具类、反射扩展)
    ↓ 基于
Avalonia Controls Framework(框架控件基类)

目录结构

Controls/
├── IMotionAwareControl.cs             # 动效感知接口
├── AnimationUtils.cs                  # 过渡动画工厂(主题感知)
├── TemplatedControlUtils.cs           # 模板控件工具
├── TransformTrackingHelper.cs         # 坐标变换追踪
├── IClickableControl.cs               # 可点击控件接口
├── VisualReflectionExtensions.cs      # Visual 反射扩展
├── ItemCollectionReflectionExtensions.cs  # ItemCollection 反射
├── ILayoutRootReflectionExtensions.cs # LayoutRoot 反射
├── StyledElementReflectionExtensions.cs   # StyledElement 反射
├── RawPointerEventArgsReflectionExtensions.cs # 指针事件反射

Input/
├── XYFocusHelpers.cs                  # XY 方向焦点导航

Reactive/
├── IAtomUISubject.cs                  # 双向响应式接口
├── LightweightObservableBase.cs       # 轻量级 Observable 基类
└── LightweightSubject.cs             # 轻量级 Subject 实现

核心组件

1. IMotionAwareControl — 动效感知接口

所有需要参与动效系统的控件都应实现此接口:

public interface IMotionAwareControl
{
    // 是否启用动效(StyledProperty,可在 XAML 中设置)
    bool IsMotionEnabled { get; set; }
    
    // 动效持续时长(StyledProperty)
    TimeSpan MotionDuration { get; set; }
}

MotionAwareControlProperty

提供静态工具方法注册 IsMotionEnabled 和 MotionDuration 的 StyledProperty,确保所有控件使用一致的属性定义。

// 在控件中注册动效属性
public static readonly StyledProperty<bool> IsMotionEnabledProperty =
    MotionAwareControlProperty.Register<MyControl>(nameof(IsMotionEnabled));

2. AnimationUtils(TransitionUtils)— 主题感知过渡工厂

与 Animations/BaseTransitionUtils 不同,AnimationUtils 创建的过渡动画会自动从主题 Token 获取动画时长:

// 创建过渡(时长自动从主题 Token 中获取)
var transition = AnimationUtils.CreateTransition<DoubleTransition>(
    targetProperty: OpacityProperty,
    tokenDuration: GlobalTokenResourceKey.MotionDurationMid
);

这实现了动画时长与主题系统的联动——当用户切换主题或禁用动效时,过渡时长自动调整。

3. TransformTrackingHelper — 坐标变换追踪

追踪控件在整个视觉树中的累积坐标变换,实时计算控件到根元素的变换矩阵。

核心功能

// 创建追踪器
var tracker = new TransformTrackingHelper(control);

// 获取控件相对于根的变换矩阵
Matrix transform = tracker.ComputedTransform;

// 监听变换变化
tracker.TransformChanged += OnTransformChanged;

实现机制

  1. 沿视觉树向上遍历到根元素
  2. 订阅每一级父元素的 TransformChanged 事件
  3. 使用 Dispatcher.InvokeAsync 延迟更新,合并同一帧内的多次变化
  4. 当视觉树结构变化时(Attached/Detached),自动重建追踪链

用于弹出层定位(Popup positioning)等需要精确坐标的场景。

4. TemplatedControlUtils — 模板控件工具

解决 Avalonia 模板控件中模板父级(TemplatedParent)传播的问题:

// 递归应用模板父级到子控件树
TemplatedControlUtils.ApplyTemplatedParentRecursively(
    rootControl, 
    templatedParent
);

在复杂的控件组合场景中,确保嵌套控件正确继承模板上下文。

5. IClickableControl — 可点击控件接口

public interface IClickableControl
{
    event EventHandler<RoutedEventArgs>? Click;
}

为所有可点击控件提供统一的点击事件契约。

6. XYFocusHelpers — XY 方向焦点导航

处理基于方向的焦点导航逻辑,根据输入设备类型验证导航模式:

// 检查控件是否启用了 XY 焦点导航
bool enabled = XYFocusHelpers.IsXYNavigationEnabled(control, deviceType);

支持的设备类型包括键盘、游戏手柄等,不同设备可能有不同的导航行为。

响应式编程基础设施(Reactive)

7. IAtomUISubject<T> — 双向响应式接口

public interface IAtomUISubject<T> : IObserver<T>, IObservable<T>
{
    // 同时是观察者和可观察对象
}

统一了 Observer 和 Observable 的角色,允许一个对象既能接收值又能发射值。

8. LightweightObservableBase<T> — 轻量级 Observable

高性能的 IObservable<T> 基类,相比 Rx 的标准实现做了多项优化:

优化策略

优化 说明
延迟初始化 订阅者列表在首次订阅时才分配
单订阅者优化 只有一个订阅者时不使用列表
线程安全 使用 lock 保护订阅者管理
结构化取消 Unsubscribed() / Subscribed() 回调支持子类响应
public abstract class LightweightObservableBase<T> : IObservable<T>
{
    protected abstract void Subscribed(IObserver<T> observer, bool first);
    protected abstract void Unsubscribed(IObserver<T> observer, bool last);
    protected void PublishNext(T value);    // 向所有订阅者发射值
    protected void PublishCompleted();       // 完成信号
    protected void PublishError(Exception e); // 错误信号
}

9. LightweightSubject<T> — 轻量级 Subject

继承 LightweightObservableBase<T>,实现 IAtomUISubject<T>:

var subject = new LightweightSubject<int>();

// 作为 Observable 被订阅
subject.Subscribe(observer);

// 作为 Observer 接收值(并转发给订阅者)
subject.OnNext(42);

反射扩展集

控件基础设施包含大量反射扩展,用于访问 Avalonia 内部 API:

扩展类 目标类型 访问内容
VisualReflectionExtensions Visual 视觉树内部状态
ItemCollectionReflectionExtensions ItemCollection 内部集合状态
ILayoutRootReflectionExtensions ILayoutRoot 布局根信息
StyledElementReflectionExtensions StyledElement LogicalChildren、TemplatedParent
RawPointerEventArgsReflectionExtensions RawPointerEventArgs 原始指针事件数据

所有反射扩展均使用 [DynamicDependency] 特性确保 AOT/Trimming 安全。

设计模式

模式 应用
接口隔离 IMotionAwareControl、IClickableControl 各自定义最小契约
观察者模式 LightweightObservableBase<T> 实现高性能的发布-订阅
中介者模式 TransformTrackingHelper 中介控件与视觉树变换
工厂模式 AnimationUtils 创建主题感知的过渡实例
访问者模式 TemplatedControlUtils 递归遍历控件树应用模板
外观模式 反射扩展类封装了复杂的反射调用为简单的方法

与其他系统的关系

  • 动画系统:IMotionAwareControl 控制控件是否参与动效,AnimationUtils 使用动画系统创建过渡
  • 主题系统:AnimationUtils 从主题 Token 获取动画时长
  • MotionScene:MotionActor 检查控件的 IMotionAwareControl 接口决定是否播放动效
  • 集合系统:ItemCollectionReflectionExtensions 访问集合内部状态

相关文档