Files
AtomUI/docs/Gallery/09-RisksAndNotes.md
chinboy 7df3f29065 docs: 添加 AtomUIGallery 项目全面分析文档
- 00-Index: 文档索引与快速导航
- 01-Overview: 项目概览、目录树、依赖关系、构建运行
- 02-Architecture: MVVM架构、模块划分、核心类职责(含Mermaid图)
- 03-ShowCaseSystem: 72个ShowCase清单、路由注册、布局系统
- 04-WorkspaceSystem: 主窗口、导航面板、菜单系统
- 05-LocalizationSystem: LanguageProvider+Source Generator架构
- 06-IconSystem: IconProvider+Source Generator架构
- 07-TechStack: 技术栈清单(C#/Avalonia/ReactiveUI等)
- 08-CodingConventions: 编码规范与ReactiveUI使用规范
- 09-RisksAndNotes: 风险、技术债、迭代检查清单
2026-04-14 17:45:49 +08:00

261 lines
8.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 潜在风险与迭代注意事项
## 1. 架构风险
### 1.1 Service Locator 反模式
**风险等级**:⚠️ 中
`CaseNavigationViewModel` 构造函数中集中注册了 72 个 ViewModel 工厂,使用 `Locator.CurrentMutable.Register` 实现服务定位。
**问题**:
- 注册代码集中在一个构造函数中,随 ShowCase 数量增长会越来越臃肿
- 字符串 Key(`EntityKey`)缺乏编译时检查,拼写错误不会报错
- 难以进行单元测试(需要 mock `Locator`)
**建议**:
- 考虑使用 Source Generator 自动生成注册代码
- 或使用模块化注册(每个 Category 独立注册)
### 1.2 ViewModel 与 View 强耦合
**风险等级**:⚠️ 中
虽然使用了 MVVM 模式,但大量 ShowCase View 的交互逻辑在 Code-Behind 中实现,直接操作控件而非通过 ViewModel。
**问题**:
- 难以对 UI 交互逻辑进行单元测试
- ViewModel 的 `RaiseAndSetIfChanged` 属性使用不充分
- 部分事件处理器包含业务逻辑(如 `Dispatcher.UIThread.InvokeAsync` + `Task.Delay`)
**建议**:
- 将可测试的逻辑迁移到 ViewModel
- 使用 ReactiveUI Command 替代 Click 事件处理器
- 保持 View Code-Behind 仅处理纯 UI 操作
### 1.3 IScreen 查找方式
**风险等级**:⚠️ 低
`CaseNavigation` 通过 `OnAttachedToLogicalTree` 向上遍历可视化树查找 `IScreen`:
```csharp
var screen = this.FindAncestorOfType<WorkspaceWindow>()?.ViewModel;
```
**问题**:
- 依赖具体的 `WorkspaceWindow` 类型而非 `IScreen` 接口
- 如果窗口类型变更,此处需要同步修改
**建议**:
- 使用 `this.FindAncestorOfType<IScreen>()` 或通过 DataContext 传递
## 2. 性能风险
### 2.1 72 个 ViewModel 同时注册
**风险等级**:⚠️ 低
所有 ViewModel 工厂在 `CaseNavigationViewModel` 构造时注册,虽然使用工厂 Lambda 延迟创建,但 `Locator` 的注册表会持续增长。
**当前缓解**:工厂 Lambda 是轻量级的,不会立即创建 ViewModel 实例。
### 2.2 ShowCase View 未缓存
**风险等级**:⚠️ 中
使用 `NavigateAndReset` 导航,每次切换 ShowCase 都会创建新的 View 和 ViewModel 实例,旧实例被丢弃。
**问题**:
- 频繁导航时产生大量 GC 压力
- 复杂 ShowCase(如 DataGrid、TreeView)初始化较慢
**建议**:
- 考虑实现 View 缓存池
- 或使用 `Navigate` 而非 `NavigateAndReset` 保持导航堆栈
### 2.3 自动测试导航间隔
**风险等级**:⚠️ 低
自动导航测试使用 300ms 固定间隔,复杂 ShowCase 可能来不及完成初始化。
**建议**:
- 根据导航目标复杂度动态调整间隔
- 或等待 View 的 `WhenActivated` 完成后再导航
## 3. 硬编码问题
### 3.1 默认导航目标
**位置**:`CaseNavigation.OnAttachedToLogicalTree`
```csharp
_navigationViewModel.NavigateTo(AboutUsViewModel.ID.ToString());
```
**问题**:默认导航到 `AboutUs` 页面,如果 `AboutUsViewModel` 被移除或重命名,此处会静默失败。
### 3.2 主题切换菜单项
**位置**:`WorkspaceWindow.HandleMenuItemCheckChanged`
菜单项通过 `MenuItem.Tag` 存储枚举值,XAML 中硬编码:
```xml
<MenuItem Tag="{x:Static local:WindowMenuItemKind.DarkMode}"/>
```
**问题**:新增菜单项需要同时修改 XAML、枚举和事件处理器,三处需保持同步。
### 3.3 测试导航间隔
**位置**:`CaseNavigationViewModel.TestNavigatePages`
```csharp
await Task.Delay(TimeSpan.FromMilliseconds(300));
```
**问题**:300ms 硬编码,无法配置。
### 3.4 语言变体硬编码
**位置**:`WorkspaceWindow.HandleMenuItemCheckChanged`
```csharp
case WindowMenuItemKind.LanguageZhCN:
application.SetLanguageVariant(LanguageVariant.zh_CN);
break;
```
**问题**:新增语言变体需要修改枚举、XAML 和事件处理器。
## 4. 遗留技术债
### 4.1 BoxPanel 已废弃
**位置**:`ShowCases/ViewModels/Layout/BoxPanelViewModel.cs`
`BoxPanel` 布局控件已废弃,但对应的 ShowCase 仍然存在。
**建议**:移除或标记为废弃。
### 4.2 CommunityToolkit.Mvvm 使用不充分
项目引用了 `CommunityToolkit.Mvvm` 包,但实际使用较少,主要依赖 ReactiveUI。
**建议**:
- 如果不需要 CommunityToolkit.Mvvm 的功能,移除引用以减少依赖
- 如果需要,统一 MVVM 框架选择
### 4.3 AOT/Trimming 未启用
**位置**:`AtomUIGallery.Desktop.csproj`
```xml
<!-- <IsTrimmable>true</IsTrimmable> -->
<!-- <PublishTrimmed>true</PublishTrimmed> -->
<!-- <PublishAot>true</PublishAot> -->
```
**问题**:
- 发布包体积较大
- 未来 .NET 趋势是 AOT 优先
**建议**:逐步启用 Trimming,添加必要的 Trimmer 根描述符。
### 4.4 缺少单元测试
Gallery 项目没有专门的测试项目,完全依赖手动测试和 F5 自动导航测试。
**建议**:
- 为 ViewModel 添加单元测试
- 为自定义控件(ShowCasePanel、ShowCaseItem 等)添加控件测试
- 使用 Avalonia.Headless 进行 UI 自动化测试
## 5. 迭代注意事项
### 5.1 新增 ShowCase 检查清单
每次新增 ShowCase 时,确保完成以下步骤:
- [ ] 创建 ViewModel(实现 `IRoutableViewModel` + `IActivatableViewModel`)
- [ ] 创建 View(继承 `ReactiveUserControl<T>`)
- [ ] 在 `CaseNavigationViewModel` 中注册工厂
- [ ] 在 `CaseNavigation.axaml` 的 `NavMenu` 中添加导航项
- [ ] 在 `CaseNavigationLang` 中添加中英文翻译
- [ ] 验证 Source Generator 正确生成枚举和扩展
- [ ] 测试导航和语言切换
### 5.2 新增控件主题检查清单
- [ ] 创建控件类(继承 `TemplatedControl`)
- [ ] 创建 ControlTheme XAML 文件
- [ ] 在 `GalleryControlThemesProvider` 中注册主题
- [ ] 在 `ThemeManagerBuilderExtensions` 中添加注册扩展
### 5.3 新增语言变体检查清单
- [ ] 为每个 `LanguageProvider` 添加新语言类
- [ ] 使用相同的 `[LanguageProvider("Name")]` 标记
- [ ] 确保所有 `const string` 字段名与现有语言类一致
- [ ] 在 `WorkspaceWindow` 菜单中添加语言切换项
- [ ] 在 `WindowMenuItemKind` 枚举中添加新值
- [ ] 在 `HandleMenuItemCheckChanged` 中添加处理逻辑
### 5.4 升级 AtomUI 版本注意事项
- Debug 配置使用 `ProjectReference`,升级源码即可
- Release 配置使用 `PackageReference`,需更新 `Directory.Packages.props` 中的版本号
- Source Generator 可能生成不同的代码,需检查 `GeneratedFiles/` 目录
- 新控件可能需要新的 ShowCase
### 5.5 升级 .NET 版本注意事项
- 修改 `Directory.Build.props` 中的 `AtomUITargetFrameworks`
- 检查 `Roots.xml` 是否需要更新(Trimmer 根描述符)
- 检查发布脚本 `PublishToLocal.ps1` 是否需要更新
- 验证跨平台兼容性
## 6. 代码质量建议
### 6.1 短期改进
1. **添加 XML 文档注释**:至少为公共 API 添加 `/// <summary>` 注释
2. **移除废弃代码**:清理 `BoxPanelViewModel` 等已废弃的 ShowCase
3. **统一 MVVM 模式**:决定使用 ReactiveUI 还是 CommunityToolkit.Mvvm,避免混用
4. **提取硬编码常量**:将 300ms 等魔法数字提取为命名常量
### 6.2 中期改进
1. **添加单元测试**:为 ViewModel 和自定义控件添加测试
2. **实现 View 缓存**:减少导航时的 GC 压力
3. **模块化注册**:将 ShowCase 注册拆分为按 Category 独立注册
4. **启用 Trimming**:减少发布包体积
### 6.3 长期改进
1. **Source Generator 自动注册**:自动扫描 ShowCase 并生成注册代码
2. **Headless UI 测试**:使用 Avalonia.Headless 进行自动化 UI 测试
3. **AOT 支持**:逐步启用 AOT 编译
4. **性能监控**:添加导航性能指标和内存使用监控
## 7. 依赖风险
### 7.1 .NET 10 预览版
当前目标框架为 `net10.0`,.NET 10 仍为预览版,可能存在 API 变更。
**缓解**:同时支持 `net8.0` 作为备选目标框架。
### 7.2 Avalonia 版本升级
Avalonia 11.x 仍在积极开发中,小版本升级可能引入破坏性变更。
**缓解**:使用 `Directory.Packages.props` 统一管理版本号。
### 7.3 ReactiveUI 与 Avalonia 集成
ReactiveUI.Avalonia 的版本需要与 Avalonia 版本兼容。
**缓解**:通过 Avalonia 包间接引用 ReactiveUI,确保版本兼容。