# Message 全局提示 ## 概述 全局提示(Message)用于在页面顶部居中展示轻量级的操作反馈信息,属于非阻断性反馈组件。它在操作完成后自动出现在页面顶部,短暂停留后自动消失,不打断用户的操作流程。适用于表单提交成功/失败、异步操作状态提示、系统信息通知等场景。 AtomUI 的 `Message` 控件对标 [Ant Design 5.0 Message](https://ant.design/components/message-cn) 的设计规范,在 .NET / Avalonia 平台上提供一致的全局提示体验。 --- ## 设计原理 ### Ant Design 的全局提示设计哲学 Ant Design 对全局提示的定位是:**「全局展示操作反馈信息,居顶部居中显示并自动消失,是一种不打断用户操作的轻量级提示方式」**。它与 Notification(通知提醒)的关键区别在于: | 特性 | Message(全局提示) | Notification(通知提醒) | |---|---|---| | **位置** | 页面顶部居中 | 页面四角 | | **内容量** | 仅文本,轻量单行 | 标题 + 详细描述 + 操作按钮 | | **交互** | 无交互,自动消失 | 可关闭、可操作 | | **适用场景** | 操作反馈(成功/失败/警告) | 需要用户关注的复杂通知 | **五种消息类型**(对应不同操作结果和语义): | 类型 | 图标 | 设计意图 | 典型用途 | |---|---|---|---| | ℹ️ **Information** | `InfoCircleFilled`(蓝色) | 普通信息提示,中性语义 | 一般性操作提示、说明信息 | | ✅ **Success** | `CheckCircleFilled`(绿色) | 操作成功确认 | 表单提交成功、保存完成 | | ⚠️ **Warning** | `ExclamationCircleFilled`(黄色) | 警告提示,需要注意 | 操作有风险但可继续 | | ❌ **Error** | `CloseCircleFilled`(红色) | 操作失败,需要关注 | 提交失败、网络错误 | | 🔄 **Loading** | `LoadingOutlined`(蓝色旋转) | 异步操作进行中 | 数据加载、文件上传中 | ### AtomUI 的架构设计 AtomUI 的 Message 系统由三个核心组件协作完成: ``` WindowMessageManager(容器管理器) ├── 挂载在 TopLevel 的 AdornerLayer 上 ├── 管理消息的生命周期(显示、自动关闭、最大数量控制) └── MessageCard(单条消息卡片)× N ├── 图标(根据 MessageType 自动匹配) ├── 文本内容 └── 入场/出场动画(MoveUpIn / MoveUpOut) ``` **职责分离**: - `IMessage` / `Message` — 数据模型,承载消息内容、类型、过期时间等信息 - `MessageCard` — 视觉控件,负责单条消息的渲染和动画 - `WindowMessageManager` — 容器管理器,负责消息的创建、排布和生命周期管理 --- ## 功能详解 ### 消息类型(MessageType) 消息类型通过 `MessageType` 枚举指定,每种类型会自动匹配对应的图标和颜色: | 类型 | 默认图标 | 图标颜色来源 | |---|---|---| | `Information` | `InfoCircleFilled` | `SharedToken.ColorPrimary`(蓝色) | | `Success` | `CheckCircleFilled` | `SharedToken.ColorSuccess`(绿色) | | `Warning` | `ExclamationCircleFilled` | `SharedToken.ColorWarning`(黄色) | | `Error` | `CloseCircleFilled` | `SharedToken.ColorError`(红色) | | `Loading` | `LoadingOutlined`(旋转) | `SharedToken.ColorPrimary`(蓝色) | ### 自动关闭与过期时间 每条消息都有 `Expiration` 属性控制自动关闭时间: - 默认值为 **5 秒** - 设置为 `TimeSpan.Zero` 时消息不会自动关闭,需要手动调用 `Close()` - 过期后通过 `DispatcherTimer.RunOnce` 触发关闭流程 ### 最大显示数量 `WindowMessageManager.MaxItems` 控制同时可见的最大消息数量(默认为 5)。当新消息导致超出上限时,最早显示的消息会被自动关闭。 ### 入场/出场动画 MessageCard 使用 `MoveUpIn` / `MoveUpOut` 动画实现消息的入场和出场效果: - **入场**:从上方滑入 + 透明度从 0 到 1,使用 `CubicEaseOut` 缓动 - **出场**:向上滑出 + 透明度从 1 到 0,使用 `CubicEaseIn` 缓动 - 动画偏移量固定为 100px(`AnimationMaxOffsetY`) - 动画时长由 `SharedToken.MotionDurationMid` 控制 - 可通过 `IsMotionEnabled = false` 禁用动画 ### 关闭回调 通过 `Message` 构造函数的 `onClose` 参数传入关闭回调,当消息关闭(无论自动或手动)时执行。这支持链式消息——在一条消息关闭后立即显示下一条。 ### 自定义图标 通过 `Message` 构造函数的 `icon` 参数可以传入自定义 `PathIcon`,覆盖默认的类型图标。 --- ## 与 Ant Design 规范的对齐程度 | 特性 | Ant Design (React) | AtomUI (Avalonia) | 对齐情况 | |---|---|---|---| | 五种消息类型 | ✅ `info / success / warning / error / loading` | ✅ `MessageType` 枚举 | ✅ 完全对齐 | | 顶部居中显示 | ✅ | ✅ `HorizontalAlignment="Center"` + `VerticalAlignment="Top"` | ✅ 完全对齐 | | 自动关闭 | ✅ 默认 3 秒 | ✅ 默认 5 秒 | ⚠️ 默认时长不同 | | 自定义图标 | ✅ `icon` 属性 | ✅ `Icon` 参数 | ✅ 对齐 | | 关闭回调 | ✅ `onClose` | ✅ `OnClose` 回调 | ✅ 对齐 | | Loading 类型 | ✅ | ✅ 旋转 `LoadingOutlined` 图标 | ✅ 完全对齐 | | 自定义时长 | ✅ `duration` 参数 | ✅ `Expiration` 参数 | ✅ 对齐 | | 最大显示数量 | ✅ `maxCount` | ✅ `MaxItems` 属性 | ✅ 对齐 | | Promise 接口 | ✅ `message.open().then(...)` | ❌ 使用回调模式 | ⚠️ C# 无 Promise,使用 `OnClose` 回调 | | 全局配置 | ✅ `message.config()` | ❌ 通过 `WindowMessageManager` 实例配置 | ⚠️ 实例级配置 vs 全局配置 | | 更新消息内容 | ✅ 通过 `key` 更新 | ✅ `Message.Content` 支持 `INotifyPropertyChanged` | ⚠️ 机制不同但功能可实现 | --- ## 继承关系 ### MessageCard ``` Avalonia.Controls.Primitives.TemplatedControl └── AtomUI.Desktop.Controls.MessageCard └── implements IMotionAwareControl ``` ### WindowMessageManager ``` Avalonia.Controls.Primitives.TemplatedControl └── AtomUI.Desktop.Controls.WindowMessageManager ├── implements IMessageManager ├── implements IMotionAwareControl └── implements IDisposable ``` ### Message(数据模型) ``` AtomUI.Desktop.Controls.Message ├── implements IMessage └── implements INotifyPropertyChanged ``` **各层级职责划分:** | 层级 | 提供的能力 | |---|---| | `TemplatedControl` | 模板化控件基础设施、`OnApplyTemplate`、`CornerRadius` 等 | | `MessageCard` | 单条消息的视觉呈现:图标自动匹配、伪类管理、入场/出场动画 | | `WindowMessageManager` | 消息容器管理:挂载到 TopLevel、消息排布、最大数量控制、自动关闭计时器 | | `Message` | 消息数据模型:内容、类型、过期时间、关闭回调 | **实现的接口:** | 接口 | 定义位置 | 控件 | 作用 | |---|---|---|---| | `IMessage` | `AtomUI.Desktop.Controls` | 数据模型 | 定义消息数据契约(Content、Type、Expiration、OnClose、Icon) | | `IMessageManager` | `AtomUI.Desktop.Controls` | WindowMessageManager | 定义消息管理器契约(`Show` 方法) | | `IMotionAwareControl` | `AtomUI.Controls` | MessageCard / WindowMessageManager | 支持动画启用/禁用控制 | | `INotifyPropertyChanged` | `System.ComponentModel` | Message | 支持属性变更通知(Content、Icon 可动态更新) | | `IDisposable` | `System` | WindowMessageManager | 支持资源释放(从 AdornerLayer 卸载、清理事件订阅) | --- ## 源码位置 | 层级 | 文件路径 | 说明 | |---|---|---| | 数据接口 | `src/AtomUI.Desktop.Controls/Message/IMessage.cs` | IMessage 消息数据契约 | | 管理器接口 | `src/AtomUI.Desktop.Controls/Message/IMessageManager.cs` | IMessageManager 管理器契约 | | 数据模型 | `src/AtomUI.Desktop.Controls/Message/Message.cs` | Message 消息数据实现 | | 消息卡片 | `src/AtomUI.Desktop.Controls/Message/MessageCard.cs` | MessageCard 视觉控件 | | 消息类型枚举 | `src/AtomUI.Desktop.Controls/Message/MessageType.cs` | MessageType 枚举 | | 伪类常量 | `src/AtomUI.Desktop.Controls/Message/MessageCardPseudoClass.cs` | 伪类常量定义 | | 容器管理器 | `src/AtomUI.Desktop.Controls/Message/WindowMessageManager.cs` | WindowMessageManager 容器 | | Token 定义 | `src/AtomUI.Desktop.Controls/Message/MessageToken.cs` | 组件级 Design Token | | 消息卡片主题 | `src/AtomUI.Desktop.Controls/Message/Themes/MessageCardTheme.axaml` | MessageCard ControlTheme | | 容器主题 | `src/AtomUI.Desktop.Controls/Message/Themes/WindowMessageManagerTheme.axaml` | WindowMessageManager ControlTheme | | 主题注册 | `src/AtomUI.Desktop.Controls/Message/Themes/MessageThemes.axaml` | 主题合并注册 | | 模板常量 | `src/AtomUI.Desktop.Controls/Message/Themes/MessageThemeConstants.cs` | 模板部件名称常量 | | Gallery 示例 | `controlgallery/AtomUIGallery/ShowCases/Views/Feedback/MessageShowCase.axaml` | 使用范例 | --- ## 模板结构 ### MessageCard 模板 MessageCard 使用 `MotionActor` 包裹以支持入场/出场动画: ``` MotionActor (PART_MotionActor) ← 动画容器 └── Border (PART_Frame) ← 主框架(背景、圆角、阴影) └── DockPanel (PART_HeaderContainer) ← 内容布局容器 ├── IconPresenter (PART_IconContent) ← 消息图标(DockPanel.Dock="Left") └── SelectableTextBlock (PART_Message) ← 消息文本(可选中复制) ``` **设计理由:** - **MotionActor 包裹**:使整个消息卡片可以参与 Move 动画,实现滑入/滑出效果 - **SelectableTextBlock**:使用可选择文本控件,用户可以选中并复制消息内容 - **DockPanel 布局**:图标靠左固定,文本填满剩余空间 ### WindowMessageManager 模板 ``` ReversibleStackPanel (PART_Items) ← 消息堆叠容器 ├── MessageCard ← 消息卡片 1 ├── MessageCard ← 消息卡片 2 └── ... ``` `ReversibleStackPanel` 支持 `ReverseOrder`,当 Position 为 `TopCenter` 时反转堆叠顺序,使最新消息出现在最上方。 ### 模板部件常量 | 常量名 | 值 | 所属 | 说明 | |---|---|---|---| | `MessageCardThemeConstants.FramePart` | `"PART_Frame"` | MessageCard | 主框架边框 | | `MessageCardThemeConstants.IconContentPart` | `"PART_IconContent"` | MessageCard | 图标展示器 | | `MessageCardThemeConstants.HeaderContainerPart` | `"PART_HeaderContainer"` | MessageCard | 内容布局容器 | | `MessageCardThemeConstants.MessagePart` | `"PART_Message"` | MessageCard | 消息文本 | | `WindowMessageManagerThemeConstants.ItemsPart` | `"PART_Items"` | WindowMessageManager | 消息列表面板 |