mirror of
https://github.com/AtomUI/AtomUI.git
synced 2026-10-26 11:10:34 +08:00
234 lines
13 KiB
Markdown
234 lines
13 KiB
Markdown
# NumericUpDown 数字输入
|
||
|
||
## 概述
|
||
|
||
数字输入框(NumericUpDown)用于输入和调整数值,支持上下步进按钮、键盘方向键和鼠标滚轮进行数值调整。它是数据录入场景中最常用的数值类控件,既能限制输入范围,又能提供便捷的步进操作。
|
||
|
||
AtomUI 的 `NumericUpDown` 控件对应 [Ant Design 5.0 InputNumber](https://ant.design/components/input-number-cn) 组件,在 .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"` | 清除按钮 |
|