Files

13 KiB
Raw Permalink Blame History

NumericUpDown 数字输入

概述

数字输入框(NumericUpDown)用于输入和调整数值,支持上下步进按钮、键盘方向键和鼠标滚轮进行数值调整。它是数据录入场景中最常用的数值类控件,既能限制输入范围,又能提供便捷的步进操作。

AtomUI 的 NumericUpDown 控件对应 Ant Design 5.0 InputNumber 组件,在 .NET / Avalonia 平台上提供与 Ant Design React 版一致的视觉体验和交互行为。


设计原理

Ant Design 的数字输入设计哲学

Ant Design 对数字输入框的定位是:「通过鼠标或键盘,输入范围内的数值」。它解决了普通文本输入框在数值场景下的几个痛点:

  • 类型安全:只允许输入有效数字,避免非法字符
  • 范围约束:通过 Minimum / Maximum 限制取值范围,步进按钮自动感知边界
  • 精确步进:通过 Increment 属性控制每次增减的步长,支持小数精度
  • 高精度模式:StringMode 支持超出 decimal 精度限制的高精度数值

三种样式变体(对齐 Ant Design 5.0 的 variant 属性):

变体 设计意图 典型用途
🔲 Outline(轮廓) 标准边框样式,视觉权重中等(默认) 表单中的标准输入场景
🔳 Filled(填充) 灰色填充背景,无明显边框 需要降低视觉权重的场景
➖ Borderless(无边框) 完全无边框,仅保留文本和步进按钮 内嵌于表格或其他控件内的紧凑场景

三种尺寸(通过 SizeType 控制):

尺寸 高度 说明
Large 40px 大号,适合触摸设备或醒目场景
Middle 32px 中号(默认),常规表单场景
Small 24px 小号,紧凑布局

Avalonia NumericUpDown 基础能力

AtomUI 的 NumericUpDown 继承自 Avalonia 框架的 Avalonia.Controls.NumericUpDown。其继承链为:

Control → TemplatedControl → ContentControl → Spinner → NumericUpDown

Avalonia NumericUpDown 提供的核心能力:

能力 说明
Value 当前数值(decimal?),支持 null 表示无值
Minimum / Maximum 取值范围约束
Increment 每次步进的增量
FormatString 显示格式化字符串
NumberFormat 自定义数字格式化对象
ParsingNumberStyle 解析样式(控制允许的数字格式)
TextConverter 自定义值与文本之间的转换器
IsReadOnly 只读模式
Text 显示的文本内容
Watermark 水印提示文本(AtomUI 通过 PlaceholderText 转发)
ValueChanged 事件 值变更时触发
ValidSpinDirection 有效步进方向(自动感知边界)

AtomUI 的扩展设计

AtomUI NumericUpDown 在 Avalonia NumericUpDown 的基础上,遵循 Ant Design 5.0 规范做了以下扩展:

扩展能力 实现方式 设计动机
三种样式变体 InputControlStyleVariant 枚举 + StyleVariant 属性 对齐 Ant Design 的 variant 属性
三种尺寸 ISizeTypeAware 接口 + SizeType 共享属性 全局统一的 Large / Middle / Small 尺寸系统
验证状态 IInputControlStatusAware + Status 属性 Error / Warning 视觉反馈
高精度字符串模式 StringMode + StringValue 属性 支持超出 decimal 精度的数值操作
键盘控制开关 Keyboard 属性 可禁止方向键调整数值
鼠标滚轮开关 MouseWheel 属性 可禁止滚轮调整数值
前后置标签 LeftAddOn / RightAddOn 属性 输入框外部的附加内容(如协议前缀)
前后置内容 InnerLeftContent / InnerRightContent 属性 输入框内部的图标或文本(如货币符号)
清除按钮 IsAllowClear + ClearIcon 属性 一键清空输入内容
占位文本 PlaceholderText / PlaceholderForeground 属性 自定义占位提示文本和颜色
紧凑空间 ICompactSpaceAware 接口 在 Space.Compact 容器中自动调整圆角和边框
表单集成 IFormItemAware 接口 可参与 FormItem 验证流程
Design Token NumericUpDownToken + RegisterTokenResourceScope 所有视觉值从全局/组件级 Token 派生

功能详解

高精度字符串模式(StringMode)

当处理超出 decimal 精度范围的数值时(如科学计算、财务高精度场景),可启用 StringMode:

  • StringMode = true 时,控件通过 StringValue 属性(string? 类型)读写原始数值字符串
  • 内部使用自定义 NumericUpDownTextConverter 绕过 decimal 精度限制
  • StringValue 和 Value 会双向同步(在可解析范围内)
  • 编辑时显示原始字符串,失焦时按格式化规则显示

键盘与鼠标控制

  • Keyboard 属性(默认 true):控制是否允许通过 Up/Down/PageUp/PageDown 键调整数值。设为 false 时,方向键事件被拦截且标记为 Handled
  • MouseWheel 属性(默认 true):控制是否允许通过鼠标滚轮调整数值。设为 false 时,滚轮事件被拦截

清除按钮

当 IsAllowClear = true 时:

  • 输入框非空且非只读时,右侧显示清除按钮(默认图标 CloseCircleFilled)
  • 点击清除按钮将 Value 设为 null
  • 可通过 ClearIcon 属性自定义清除图标

前后置内容

NumericUpDown 支持两级内容附加:

类型 属性 位置 说明
外部标签 LeftAddOn / RightAddOn 输入框外部两侧 有独立背景的附加区域(如 http://、.com)
内部内容 InnerLeftContent / InnerRightContent 输入框内部两侧 嵌入输入框内的图标或文本(如 ¥、RMB)

表单集成

通过 IFormItemAware 接口,NumericUpDown 可作为 FormItem 的子控件:

  • SetFormValue / GetFormValue / ClearFormValue 操作 Value 属性
  • NotifyValidateStatus 将表单验证状态映射到 Status 属性(Error → InputControlStatus.Error,Warning → InputControlStatus.Warning)

与 Ant Design 规范的对齐程度

特性 Ant Design (React) AtomUI (Avalonia) 对齐情况
数值输入 ✅ value / onChange ✅ Value / ValueChanged ✅ 完全对齐
最小/最大值 ✅ min / max ✅ Minimum / Maximum ✅ 完全对齐
步长 ✅ step ✅ Increment ✅ 完全对齐
三种尺寸 size ✅ large / middle / small ✅ SizeType 属性 ✅ 完全对齐
三种变体 variant ✅ outlined / filled / borderless ✅ StyleVariant 属性 ✅ 完全对齐
验证状态 status ✅ error / warning ✅ Status 属性 ✅ 完全对齐
高精度 stringMode ✅ 布尔属性 ✅ StringMode + StringValue ✅ 完全对齐
键盘控制 keyboard ✅ 布尔属性 ✅ Keyboard 属性 ✅ 完全对齐
鼠标滚轮 changeOnWheel ✅ 5.14.0 新增 ✅ MouseWheel 属性 ✅ 完全对齐
前后置标签 addonBefore/After ✅ ReactNode ✅ LeftAddOn / RightAddOn ✅ 完全对齐
前后置内容 prefix/suffix ✅ ReactNode ✅ InnerLeftContent / InnerRightContent ✅ 完全对齐
清除 ✅ allowClear 5.21 ✅ IsAllowClear ✅ 完全对齐
占位文本 placeholder ✅ 字符串 ✅ PlaceholderText ✅ 完全对齐
禁用 disabled ✅ 布尔属性 ✅ IsEnabled 取反 ✅ 完全对齐
只读 readOnly ✅ 布尔属性 ✅ IsReadOnly ✅ 完全对齐
格式化 formatter/parser ✅ 函数 ⚠️ FormatString + TextConverter ⚠️ 机制不同,语义对齐
控件宽度 controls ✅ 控制步进按钮显隐 ❌ 暂未暴露公共属性 ⚠️ 通过 ButtonSpinner 可间接控制

继承关系

Avalonia.Controls.Primitives.TemplatedControl
  └── Avalonia.Controls.ContentControl
        └── Avalonia.Controls.Primitives.Spinner
              └── Avalonia.Controls.NumericUpDown
                    └── AtomUI.Desktop.Controls.NumericUpDown
                          ├── implements ISizeTypeAware
                          ├── implements IMotionAwareControl
                          ├── implements ICompactSpaceAware
                          ├── implements IFormItemAware
                          ├── implements IInputControlStatusAware
                          └── implements IInputControlStyleVariantAware

NumericUpDown 通过 using AvaloniaNumericUpDown = Avalonia.Controls.NumericUpDown; 别名引用 Avalonia 原生控件,避免类名冲突。

注意:与 Button/Tag 等控件不同,NumericUpDown 没有在 AtomUI.Controls 中定义 Abstract* 基类,而是直接继承 Avalonia 内置的 NumericUpDown。这是因为数字输入框的核心行为(数值解析、步进、范围校验)在 Avalonia 层已经完备,AtomUI 主要在其上叠加 Ant Design 样式体系。

各层级职责划分:

层级 提供的能力
Spinner 步进事件(Spin)、步进方向验证(ValidSpinDirection)基础设施
Avalonia.Controls.NumericUpDown Value / Minimum / Maximum / Increment 数值管理、文本解析与格式化、ValueChanged 事件
AtomUI.Desktop.Controls.NumericUpDown Ant Design 视觉体系(三种变体/三种尺寸/验证状态)、Design Token 集成、StringMode 高精度、键盘/滚轮控制开关、AddOn 附加内容、清除按钮、表单集成

实现的共享接口:

接口 定义位置 作用
ISizeTypeAware AtomUI.Controls.Shared 支持 SizeType(Small / Middle / Large)三种尺寸切换
IMotionAwareControl AtomUI.Controls.Shared 支持 IsMotionEnabled 动画开关
ICompactSpaceAware AtomUI.Controls.Shared 在 Space.Compact 中使用时自动调整圆角和边框
IFormItemAware AtomUI.Controls.Shared 可作为 FormItem 的子控件参与表单验证
IInputControlStatusAware AtomUI.Controls.Shared 支持 Error / Warning 验证状态视觉反馈
IInputControlStyleVariantAware AtomUI.Controls.Shared 支持 Outline / Filled / Borderless 样式变体

源码位置

层级 文件路径 说明
控件类 src/AtomUI.Desktop.Controls/NumericUpDown/NumericUpDown.cs 桌面端 NumericUpDown 实现
Token 定义 src/AtomUI.Desktop.Controls/NumericUpDown/NumericUpDownToken.cs 组件级 Design Token
主题模板 src/AtomUI.Desktop.Controls/NumericUpDown/Themes/NumericUpDownTheme.axaml ControlTheme AXAML
模板常量 src/AtomUI.Desktop.Controls/NumericUpDown/Themes/NumericUpDownThemeConstants.cs 模板部件名称常量
Gallery 示例 controlgallery/AtomUIGallery/ShowCases/Views/DataEntry/NumberUpDownShowCase.axaml 使用范例
Gallery ViewModel controlgallery/AtomUIGallery/ShowCases/ViewModels/DataEntry/NumberUpDownViewModel.cs 范例 ViewModel

模板结构

NumericUpDown 的 ControlTemplate 委托给 ButtonSpinner 实现核心布局:

ButtonSpinner (PART_Spinner)                          ← 步进按钮容器(含 AddOn 装饰框)
  ├── [LeftAddOn]                                     ← 外部左侧标签(可选)
  ├── AddOnDecoratedBox (内部主体区域)
  │     ├── [InnerLeftContent]                        ← 内部左侧内容(前缀图标/文字)
  │     ├── TextBox (PART_TextBox)                    ← 核心文本输入框
  │     ├── StackPanel (InnerRightContent)            ← 内部右侧内容组合
  │     │     ├── InputClearIconButton (PART_ClearButton)  ← 清除按钮(条件显示)
  │     │     └── ContentPresenter                    ← 自定义内部右侧内容
  │     └── ButtonSpinnerHandle                       ← 上下步进按钮区域
  │           ├── IconButton (IncreaseButton ▲)       ← 增加按钮
  │           └── IconButton (DecreaseButton ▼)       ← 减少按钮
  └── [RightAddOn]                                    ← 外部右侧标签(可选)

布局设计要点:

  • 委托模式:NumericUpDown 不直接定义复杂模板,而是将布局委托给 ButtonSpinner,后者包含了完整的 AddOn 装饰框和步进按钮基础设施
  • 悬浮步进按钮:通过 IsButtonSpinnerFloatable="True",步进按钮在鼠标悬停时浮动显示,不占用固定宽度
  • 清除按钮与右侧内容并列:通过 StackPanel 将清除按钮和自定义右侧内容水平排列
  • 占位文本:通过 PlaceholderText 转发到内部 TextBox 的同名属性

模板部件常量

常量名 值 说明
NumericUpDownThemeConstants.SpinnerPart "PART_Spinner" ButtonSpinner 步进容器
NumericUpDownThemeConstants.ClearButtonPart "PART_ClearButton" 清除按钮