# AtomUI Gallery — 风险点、技术债与迭代注意事项 > **文档版本**:2026-04-15 --- ## 1. 技术债与已知问题 ### 1.1 ⚠️ 文件命名不规范 以下文件使用了非标准扩展名,可能导致 IDE 关联错误或构建问题: | 文件 | 问题 | 建议 | |---|---|---| | `FormShowCase.axmal.cs` | `.axmal` 拼写错误(应为 `.axaml`) | 重命名为 `FormShowCase.axaml.cs` | | `RateShowCase.axmal.cs` | 同上 | 重命名为 `RateShowCase.axaml.cs` | | `TourShowCase.axmal.cs` | 同上 | 重命名为 `TourShowCase.axaml.cs` | | `ResultShowCase.cs.axaml` | `.cs.axaml` 顺序反转(应为 `.axaml` 单独文件) | 重命名为 `ResultShowCase.axaml`,代码后置改为 `ResultShowCase.axaml.cs` | | `CustomizeThemeShowCase.cs` | 代码后置直接 `.cs`(对应 `.axaml` 存在) | 重命名为 `CustomizeThemeShowCase.axaml.cs` | > **风险**:在某些 IDE 或工具链中,文件关联可能断裂,导致 XAML 设计器无法正常工作。 ### 1.2 ⚠️ IActivatableViewModel 使用不一致 在 67 个 ShowCase ViewModel 中: - **仅 8 个**实现了 `IActivatableViewModel`(AboutUs、Button、OsInfo、Avatar、Badge、AutoComplete、Cascader、CheckBox) - **其余 59 个**未实现 然而,**所有 View** 都在构造函数中调用了 `this.WhenActivated(disposables => { ... })`。 **影响**: - 对于未实现 `IActivatableViewModel` 的 ViewModel,`WhenActivated` 仍然可以在 View 端正常工作(因为 `ReactiveUserControl` 自身支持激活) - 但如果未来需要在 ViewModel 端监听激活/反激活事件,需要逐一添加 `IActivatableViewModel` **建议**:统一规范 — 要么所有 ViewModel 都实现 `IActivatableViewModel`,要么都不实现。 ### 1.3 ⚠️ 双重注册机制 每新增一个 ShowCase 需要在 **三个位置** 手动注册: 1. `ShowCaseViewModule.RegisterViews()` — VM → View 映射 2. `CaseNavigationViewModel.RegisterShowCaseViewModels()` — VM 工厂 3. `CaseNavigation.axaml` — 导航菜单项 加上本地化资源(`en_US.cs` + `zh_CN.cs`),总计 **5 个文件** 需要同步修改。 **风险**:遗漏任何一处都会导致运行时错误或功能缺失。 **建议**:未来可考虑使用源代码生成器或反射注册自动化此流程。但鉴于当前 AOT 兼容性要求,显式注册是正确选择。 ### 1.4 ⚠️ Roots.xml 中的过时引用 `AtomUIGallery.Desktop/Roots.xml` 中包含过时的程序集名称: ```xml ``` **建议**:修正为正确的程序集名称。 ### 1.5 ⚠️ LinuxDistributionDetector 代码量过大 `LinuxDistributionDetector.cs` 共 **380 行**,包含大量平台特定检测逻辑。该工具类仅被 OsInfo ShowCase 使用。 **建议**:考虑是否可以简化或使用第三方库替代。 ### 1.6 ⚠️ CommunityToolkit.Mvvm 使用不充分 项目引用了 `CommunityToolkit.Mvvm` 包(8.4.2),但实际使用较少,核心 MVVM 依赖 ReactiveUI。 **建议**: - 如果不需要 CommunityToolkit.Mvvm 的功能,移除引用以减少依赖 - 如果需要,明确其使用场景并统一规范 --- ## 2. 架构风险点 ### 2.1 反射使用(AOT 兼容性) 以下位置使用了反射,在 AOT/NativeAOT 环境下需要特别注意: | 位置 | 反射用途 | AOT 风险 | |---|---|---| | `IconGallery.ReLoadIcons()` | 通过 `CachedLoadedAssemblyTypeScanner` 扫描 `AtomUI.Icons.AntDesign` 程序集中所有 `Icon` 子类 | ⚠️ 高 — 需要 Trimmer 保留 | | `GalleryIconProvider.GetTypeForKind()` | `Type.GetType()` + `Assembly.GetType()` 反射加载图标类型 | ⚠️ 高 | | `EnumExtension.ProvideValue()` | `Enum.GetValuesAsUnderlyingType()` | 低风险 | **缓解措施**:`Roots.xml` 中已标记相关程序集 `preserve="All"`,但需确保列表准确。 ### 2.2 每次导航创建新 View 实例 `ShowCaseViewModule` 中的工厂每次都创建新的 View: ```csharp locator.Map(() => new ButtonShowCase()); ``` 同时 `CaseNavigationViewModel.NavigateTo()` 每次都创建新的 ViewModel。 **影响**: - 内存:旧 View/ViewModel 依赖 GC 回收 - 性能:复杂 ShowCase(如 DataGrid、IconGallery)每次切换都需重新初始化 - 状态丢失:切换回已访问的 ShowCase 时所有状态重置 **建议**:对于性能敏感的 ShowCase,可考虑添加 ViewModel/View 缓存策略。 ### 2.3 事件处理与 Dispose 不一致 部分 ShowCase View(如 `ModalShowCase`)在 `WhenActivated` 中正确使用 `CompositeDisposable` 管理事件订阅生命周期: ```csharp this.WhenActivated(disposables => { BasicOpenModalButton.Click += HandleBasicModalButtonClick; disposables.Add(Disposable.Create(() => BasicOpenModalButton.Click -= HandleBasicModalButtonClick)); }); ``` 但其他 ShowCase View 虽然调用了 `WhenActivated`,却只是空回调 `disposables => { }`。 **风险**:如果 View 中直接在构造函数外订阅事件且未取消,可能导致内存泄漏。 --- ## 3. 构建与发布注意事项 ### 3.1 Debug vs Release 依赖差异 - **Debug**:使用 `` 直接引用本地 AtomUI 源码(便于调试) - **Release**:使用 `` 引用 NuGet 包(发布独立可用) 修改 AtomUI 控件源码后,必须确保 Debug 和 Release 都能正常编译。 ### 3.2 源代码生成器输出 - `GeneratedFiles/` 目录会自动由 Roslyn 生成器填充 - `` 确保不会重复编译 - **禁止手动编辑** `GeneratedFiles/` 下的文件 ### 3.3 安装包构建 `AtomUIGallery.Desktop` 包含多平台安装包配置: - **macOS**:DMG(`InstallerConfig.dmg.xml`) - **Windows**:WiX MSI(`InstallerConfig.wix.xml`) - **Linux**:AppImage(`InstallerConfig.appimage.xml`) 发布脚本:`scripts/PublishToLocal.ps1` --- ## 4. 性能注意事项 ### 4.1 图标画廊加载 `IconGallery` 使用反射扫描 + `FrozenSet` 缓存,首次加载时会扫描整个 `AtomUI.Icons.AntDesign` 程序集。虽然有 5 秒缓存超时机制,但首次加载可能较慢。 ### 4.2 自动遍历测试 F5 自动遍历以 300ms 间隔切换页面,由于每次创建新 View/ViewModel,长时间运行可能导致内存增长。这是预期行为(用于压力测试),但需关注 GC 表现。 --- ## 5. 迭代开发检查清单 新增或修改 ShowCase 时,务必完成以下检查: - [ ] ViewModel 正确实现 `IRoutableViewModel`,`ID` 唯一 - [ ] View 继承 `ReactiveUserControl`,构造函数中调用 `WhenActivated` + `InitializeComponent` - [ ] `ShowCaseViewModule.RegisterViews()` 中注册 VM → View 映射 - [ ] `CaseNavigationViewModel` 中注册 VM 工厂 - [ ] `CaseNavigation.axaml` 中添加导航菜单项 - [ ] `en_US.cs` 和 `zh_CN.cs` 中添加本地化字符串 - [ ] 亮色主题下正常显示 - [ ] 暗色主题下正常显示 - [ ] 紧凑模式下正常显示 - [ ] 中文/英文语言切换正常 - [ ] F5 自动遍历不崩溃 - [ ] `ShowCaseItem` 的 `Title` 和 `Description` 准确描述功能 - [ ] 文件命名遵循 `.axaml` + `.axaml.cs` 标准(不要写错为 `.axmal`) --- ## 6. 未来改进建议 | 优先级 | 建议 | 说明 | |---|---|---| | 🔴 高 | 修复文件命名错误 | 修正 `.axmal` 拼写错误和 `.cs.axaml` 顺序反转 | | 🔴 高 | 修正 `Roots.xml` 过时引用 | 确保 Trimmer 配置正确 | | 🟡 中 | 统一 `IActivatableViewModel` 使用 | 要么全部实现,要么全部移除 | | 🟡 中 | 考虑 ViewModel/View 缓存策略 | 避免重复创建复杂控件 | | 🟢 低 | 添加 ShowCase 自动注册 | 减少手动维护成本(需平衡 AOT 兼容性) | | 🟢 低 | 简化 `LinuxDistributionDetector` | 考虑使用第三方库或精简逻辑 |