From b04823565751daf6d2232ff4c0f174d70ad5e826 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Tue, 30 Sep 2025 22:17:48 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=B6=E6=AE=B5=E4=B8=80=EF=BC=9A=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E5=86=97=E4=BD=99=E7=9A=84UIStateMachine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 src/Core/UIStateMachine.cs - UIStateMachine和UIState枚举完全未使用 - 项目实际使用PathEditState作为状态管理 - 编译验证通过,无任何错误 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- doc/requirement/todo_features.md | 1 + doc/working/code_cleanup_plan.md | 225 ++++++++++ src/Core/UIStateMachine.cs | 744 ------------------------------- 3 files changed, 226 insertions(+), 744 deletions(-) create mode 100644 doc/working/code_cleanup_plan.md delete mode 100644 src/Core/UIStateMachine.cs diff --git a/doc/requirement/todo_features.md b/doc/requirement/todo_features.md index f898ad9..b5e0aa1 100644 --- a/doc/requirement/todo_features.md +++ b/doc/requirement/todo_features.md @@ -5,6 +5,7 @@ ### [2025/09/29] 1. [x] (功能)导出导航地图为图片 +2. [x] (功能)增加时间标签功能,以限速和路径段评估路径运行时间 ### [2025/09/28] diff --git a/doc/working/code_cleanup_plan.md b/doc/working/code_cleanup_plan.md new file mode 100644 index 0000000..efaf634 --- /dev/null +++ b/doc/working/code_cleanup_plan.md @@ -0,0 +1,225 @@ +# NavisworksTransport 代码清理方案 + +**创建日期**: 2025-09-30 +**目标**: 清理冗余代码、消除重复功能、移除向后兼容逻辑 + +## 执行原则 + +遵循CLAUDE.md中的开发原则: + +- ✅ 让问题快速暴露 > 让程序看起来正常运行 +- ✅ 报错比静默失败好 +- ✅ 最小化修改 > 复杂全面的逻辑 +- ✅ 明确拒绝向后兼容性 + +## 一、UI状态管理冗余清理 + +### 1.1 问题分析 + +**重复系统**: + +- `UIStateManager` (src/Core/UIStateManager.cs) - 线程安全的UI更新队列机制 +- `UIStateMachine` (src/Core/UIStateMachine.cs) - UI状态转换和历史跟踪 + +**问题**: + +- 两者都是单例模式 +- 都处理UI线程同步 +- UIStateMachine依赖UIStateManager进行UI更新 +- 造成双重抽象,增加复杂度 + +### 1.2 清理方案 + +**保留**: `UIStateManager` - 核心UI线程调度器 + +**删除**: `UIStateMachine` 及相关文件 + +- src/Core/UIStateMachine.cs + +**迁移策略**: + +1. 检查所有引用UIStateMachine的代码 +2. 将状态枚举(UIState)迁移到独立文件或PathPlanningModels +3. 将状态转换逻辑简化为直接的状态变更 +4. 移除状态历史跟踪(过度设计) + +### 1.3 UIUpdate框架简化(可选) + +**问题**:src/Core/UIUpdate/ 目录包含完整框架(8个文件),但实际使用率低 + +**方案A(激进)**:删除整个UIUpdate框架,统一使用UIStateManager +**方案B(保守)**:保留UIUpdateService核心,删除监控和复杂功能 + +**建议**:采用方案A - 当前项目规模不需要如此复杂的UI更新框架 + +## 二、动画管理器合并 + +### 2.1 问题分析 + +**两个动画管理器**: + +- `PathAnimationManager` - 基于Transform的通用动画 +- `LogisticsAnimationManager` - 针对Navisworks 2026优化 + +**使用情况**: + +- AnimationControlViewModel 同时实例化两者 +- StartAnimationCommand 使用 LogisticsAnimationManager +- 功能有重叠 + +### 2.2 清理方案 + +**保留**: `LogisticsAnimationManager` - 符合2026专属策略 + +**删除**: `PathAnimationManager` 及相关代码 + +- src/Core/Animation/PathAnimationManager.cs +- AnimationFrame, AnimationState, CollisionPair 等辅助类(如果LogisticsAnimationManager不需要) + +**迁移步骤**: + +1. 检查PathAnimationManager中是否有LogisticsAnimationManager缺少的功能 +2. 将必要功能迁移到LogisticsAnimationManager +3. 更新AnimationControlViewModel只使用LogisticsAnimationManager +4. 删除PathAnimationManager文件 + +## 三、WPF Services清理 + +### 3.1 零使用率类删除 + +**立即删除**: + +- `DataBindingBestPractices` (src/UI/WPF/Services/DataBindingBestPractices.cs) - 0次外部引用 +- `CrossViewModelSynchronizer` (src/UI/WPF/Services/CrossViewModelSynchronizer.cs) - 仅被BestPractices使用 + +### 3.2 虚拟化集合(可选) + +**文件**: src/UI/WPF/Collections/VirtualizedObservableCollection.cs + +**问题**: 只被DataBindingBestPractices引用,无实际业务使用 + +**建议**: 删除(如果未来需要处理大数据集,重新实现更简单) + +### 3.3 保留的Services + +**保留并继续使用**: + +- `SmartDataBindingOptimizer` - ViewModelBase依赖 +- `BindingExpressionOptimizer` - SmartDataBindingOptimizer依赖 +- `DataBindingPerformanceMonitor` - 多处使用(可考虑简化) + +## 四、向后兼容代码清理 + +### 4.1 明确标注的旧版代码 + +**删除位置**: + +1. **PathAnimationManager.cs** + - Line 143: `public event EventHandler AnimationCompleted;` - 旧版事件 + - Line 904: `AnimationCompleted?.Invoke(this, EventArgs.Empty);` - 触发旧版事件 + - 注释:"旧版,保留兼容性" / "保持兼容性" + +2. **ModelSplitterManager.cs** + - Line 1584-1593: `GenerateFileName(string layerName, SplitConfiguration config)` 方法 + - 注释:"旧版本兼容性方法" + - 方案:删除此重载,统一使用带Strategy参数的新版本 + +3. **LayerManagementViewModel.cs** + - Line 1712: 类似的`GenerateFileName`旧版方法 + - 统一使用新版本实现 + +### 4.2 清理原则 + +- 遇到"旧版"、"兼容"、"fallback"等标注,直接删除 +- 不做任何"备用方案"或"容错处理" +- 如有问题,让它快速暴露 + +## 五、辅助文件清理 + +### 5.1 临时文档 + +**检查并删除**: + +- `path_visualization_ui.txt` - XAML代码片段,确认已集成到代码后删除 + +### 5.2 不删除的文件 + +以下管理器使用率合理,保留: + +- PathInputMonitor (58次引用) +- IdleEventManager (58次引用) +- DocumentStateManager (58次引用) + +## 执行计划 + +### 阶段一:UI状态管理清理(高风险) + +1. [ ] 分析UIStateMachine所有引用点 +2. [ ] 迁移UIState枚举到PathPlanningModels +3. [ ] 更新所有引用UIStateMachine的代码改用简单状态 +4. [ ] 删除UIStateMachine.cs +5. [ ] 编译验证 + +### 阶段二:动画管理器合并(中风险) + +1. [ ] 对比两个动画管理器的功能差异 +2. [ ] 将PathAnimationManager独有功能迁移到LogisticsAnimationManager +3. [ ] 更新AnimationControlViewModel +4. [ ] 删除PathAnimationManager.cs +5. [ ] 编译验证 + +### 阶段三:WPF Services清理(低风险) + +1. [ ] 删除DataBindingBestPractices.cs +2. [ ] 删除CrossViewModelSynchronizer.cs +3. [ ] 删除VirtualizedObservableCollection.cs +4. [ ] 编译验证 + +### 阶段四:向后兼容代码清理(低风险) + +1. [ ] 删除PathAnimationManager的AnimationCompleted事件及触发代码 +2. [ ] 删除ModelSplitterManager的旧版GenerateFileName +3. [ ] 删除LayerManagementViewModel的旧版GenerateFileName +4. [ ] 编译验证 + +### 阶段五:最终验证 + +1. [ ] 完整编译 +2. [ ] 运行单元测试 +3. [ ] 删除path_visualization_ui.txt +4. [ ] 更新CHANGELOG.md +5. [ ] Git commit + +## 预期效果 + +**代码减少**: + +- 删除文件:约8-10个 +- 减少代码行数:约3000-5000行 + +**架构改进**: + +- 消除UI状态管理的重复抽象 +- 统一动画管理接口 +- 移除未使用的优化工具 +- 清除所有向后兼容负担 + +**风险评估**: + +- 高风险:UI状态管理重构(需要仔细测试) +- 中风险:动画管理器合并(可能影响现有功能) +- 低风险:删除未使用的Services和兼容代码 + +## 回滚策略 + +每个阶段完成后创建Git commit,便于回滚: + +```bash +git commit -m "阶段X: [具体内容]" +``` + +如遇问题: + +```bash +git revert HEAD # 回滚最后一次提交 +``` diff --git a/src/Core/UIStateMachine.cs b/src/Core/UIStateMachine.cs deleted file mode 100644 index d2fff36..0000000 --- a/src/Core/UIStateMachine.cs +++ /dev/null @@ -1,744 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using NavisworksTransport.Utils; - -namespace NavisworksTransport.Core -{ - /// - /// UI状态机 - 管理整个应用的UI状态转换 - /// 提供线程安全的状态管理、状态转换验证和历史跟踪功能 - /// 集成UIStateManager进行状态变更的UI通知 - /// - public class UIStateMachine - { - #region 字段和属性 - - private static UIStateMachine _instance; - private static readonly object _instanceLock = new object(); - - private UIState _currentState = UIState.Idle; - private readonly object _stateLock = new object(); - private readonly UIStateManager _uiStateManager; - - // 状态历史记录 - private readonly List _stateHistory = new List(); - private readonly int _maxHistoryRecords = 100; // 最大历史记录数 - - // 状态转换验证规则 - private readonly Dictionary> _allowedTransitions; - - // 状态变更事件 - public event EventHandler StateChanged; - public event EventHandler StateTransitioning; - - /// - /// 获取UIStateMachine的单例实例 - /// - public static UIStateMachine Instance - { - get - { - if (_instance == null) - { - lock (_instanceLock) - { - if (_instance == null) - { - _instance = new UIStateMachine(); - } - } - } - return _instance; - } - } - - /// - /// 获取当前UI状态(线程安全) - /// - public UIState CurrentState - { - get - { - lock (_stateLock) - { - return _currentState; - } - } - } - - /// - /// 获取状态历史记录的快照 - /// - public StateTransitionRecord[] StateHistory - { - get - { - lock (_stateLock) - { - return _stateHistory.ToArray(); - } - } - } - - /// - /// 获取当前状态描述 - /// - public string CurrentStateDescription => GetStateDescription(CurrentState); - - /// - /// 获取当前状态是否为忙碌状态 - /// - public bool IsBusy => IsStateStrictBusy(CurrentState); - - #endregion - - #region 构造函数 - - private UIStateMachine() - { - try - { - _uiStateManager = UIStateManager.Instance; - _allowedTransitions = InitializeStateTransitions(); - - LogManager.Info("UIStateMachine初始化完成"); - } - catch (Exception ex) - { - LogManager.Error($"UIStateMachine初始化失败: {ex.Message}"); - throw; - } - } - - /// - /// 初始化状态转换规则 - /// - /// 状态转换规则字典 - private Dictionary> InitializeStateTransitions() - { - var transitions = new Dictionary>(); - - // Idle状态可以转换到任何状态 - transitions[UIState.Idle] = new HashSet - { - UIState.Planning, - UIState.Updating, - UIState.Animating, - UIState.Error, - UIState.Loading, - UIState.Exporting, - UIState.Editing - }; - - // Planning状态的转换 - transitions[UIState.Planning] = new HashSet - { - UIState.Idle, - UIState.Updating, - UIState.Error, - UIState.Editing - }; - - // Updating状态的转换 - transitions[UIState.Updating] = new HashSet - { - UIState.Idle, - UIState.Planning, - UIState.Error, - UIState.Animating - }; - - // Animating状态的转换 - transitions[UIState.Animating] = new HashSet - { - UIState.Idle, - UIState.Updating, - UIState.Error - }; - - // Loading状态的转换 - transitions[UIState.Loading] = new HashSet - { - UIState.Idle, - UIState.Error, - UIState.Planning - }; - - // Exporting状态的转换 - transitions[UIState.Exporting] = new HashSet - { - UIState.Idle, - UIState.Error - }; - - // Editing状态的转换 - transitions[UIState.Editing] = new HashSet - { - UIState.Idle, - UIState.Planning, - UIState.Updating, - UIState.Error - }; - - // Error状态可以转换到Idle或回到任何正常状态 - transitions[UIState.Error] = new HashSet - { - UIState.Idle, - UIState.Planning, - UIState.Updating, - UIState.Animating, - UIState.Loading, - UIState.Exporting, - UIState.Editing - }; - - return transitions; - } - - #endregion - - #region 状态转换核心方法 - - /// - /// 尝试转换状态(线程安全) - /// - /// 目标状态 - /// 转换上下文信息 - /// 转换是否成功 - public bool TryTransition(UIState newState, string context = null) - { - var currentState = CurrentState; - - // 如果是相同状态,直接返回true - if (currentState == newState) - { - LogManager.Debug($"UIStateMachine状态转换跳过: 已处于{GetStateDescription(newState)}状态"); - return true; - } - - // 验证转换是否被允许 - if (!IsTransitionAllowed(currentState, newState)) - { - LogManager.Warning($"UIStateMachine非法状态转换: {GetStateDescription(currentState)} -> {GetStateDescription(newState)}"); - return false; - } - - return ExecuteStateTransition(currentState, newState, context); - } - - /// - /// 强制转换状态(用于错误恢复) - /// - /// 目标状态 - /// 转换上下文信息 - /// 转换是否成功 - public bool ForceTransition(UIState newState, string context = "强制转换") - { - var currentState = CurrentState; - LogManager.Warning($"UIStateMachine强制状态转换: {GetStateDescription(currentState)} -> {GetStateDescription(newState)}"); - - return ExecuteStateTransition(currentState, newState, context); - } - - /// - /// 执行状态转换的核心逻辑 - /// - /// 源状态 - /// 目标状态 - /// 转换上下文 - /// 转换是否成功 - private bool ExecuteStateTransition(UIState fromState, UIState toState, string context) - { - lock (_stateLock) - { - try - { - // 触发状态转换前事件 - var transitionArgs = new StateTransitionEventArgs(fromState, toState, context); - OnStateTransitioning(transitionArgs); - - // 如果事件处理器取消了转换 - if (transitionArgs.Cancel) - { - LogManager.Info($"UIStateMachine状态转换被取消: {GetStateDescription(fromState)} -> {GetStateDescription(toState)}"); - return false; - } - - // 更新状态 - _currentState = toState; - - // 记录状态历史 - RecordStateTransition(fromState, toState, context); - - // 触发状态变更事件 - var changedArgs = new StateChangedEventArgs(fromState, toState, context); - OnStateChanged(changedArgs); - - LogManager.Info($"UIStateMachine状态转换成功: {GetStateDescription(fromState)} -> {GetStateDescription(toState)}"); - - return true; - } - catch (Exception ex) - { - LogManager.Error($"UIStateMachine状态转换失败: {ex.Message}"); - return false; - } - } - } - - /// - /// 验证状态转换是否被允许 - /// - /// 源状态 - /// 目标状态 - /// 转换是否被允许 - private bool IsTransitionAllowed(UIState fromState, UIState toState) - { - if (_allowedTransitions.ContainsKey(fromState)) - { - return _allowedTransitions[fromState].Contains(toState); - } - - // 如果没有定义转换规则,默认允许转换到Error和Idle状态 - return toState == UIState.Error || toState == UIState.Idle; - } - - #endregion - - #region 状态历史和查询方法 - - /// - /// 记录状态转换历史 - /// - /// 源状态 - /// 目标状态 - /// 转换上下文 - private void RecordStateTransition(UIState fromState, UIState toState, string context) - { - var record = new StateTransitionRecord - { - FromState = fromState, - ToState = toState, - Context = context ?? string.Empty, - Timestamp = DateTime.UtcNow - }; - - _stateHistory.Add(record); - - // 清理过多的历史记录 - if (_stateHistory.Count > _maxHistoryRecords) - { - _stateHistory.RemoveAt(0); - } - } - - /// - /// 获取指定时间范围内的状态历史 - /// - /// 起始时间 - /// 状态转换记录数组 - public StateTransitionRecord[] GetStateHistorySince(DateTime since) - { - lock (_stateLock) - { - return _stateHistory.Where(record => record.Timestamp >= since).ToArray(); - } - } - - /// - /// 获取最近的N条状态历史记录 - /// - /// 记录数量 - /// 状态转换记录数组 - public StateTransitionRecord[] GetRecentStateHistory(int count = 10) - { - lock (_stateLock) - { - var takeCount = Math.Min(count, _stateHistory.Count); - return _stateHistory.Skip(_stateHistory.Count - takeCount).ToArray(); - } - } - - /// - /// 清空状态历史记录 - /// - public void ClearStateHistory() - { - lock (_stateLock) - { - _stateHistory.Clear(); - LogManager.Info("UIStateMachine状态历史已清空"); - } - } - - #endregion - - #region 状态回滚功能 - - /// - /// 回滚到上一个状态 - /// - /// 回滚是否成功 - public bool RollbackToPreviousState() - { - lock (_stateLock) - { - if (_stateHistory.Count >= 2) - { - // 获取倒数第二条记录的FromState - var previousRecord = _stateHistory[_stateHistory.Count - 2]; - var targetState = previousRecord.ToState; - - return TryTransition(targetState, "状态回滚"); - } - - LogManager.Warning("UIStateMachine无法回滚: 没有足够的状态历史"); - return false; - } - } - - /// - /// 回滚到指定状态 - /// - /// 目标状态 - /// 回滚是否成功 - public bool RollbackToState(UIState targetState) - { - return TryTransition(targetState, $"回滚到{GetStateDescription(targetState)}状态"); - } - - #endregion - - #region 实用工具方法 - - /// - /// 获取状态的中文描述 - /// - /// UI状态 - /// 状态描述 - public static string GetStateDescription(UIState state) - { - switch (state) - { - case UIState.Idle: - return "空闲"; - case UIState.Planning: - return "路径规划中"; - case UIState.Updating: - return "更新中"; - case UIState.Animating: - return "动画播放中"; - case UIState.Loading: - return "加载中"; - case UIState.Exporting: - return "导出中"; - case UIState.Editing: - return "编辑中"; - case UIState.Error: - return "错误状态"; - default: - return "未知状态"; - } - } - - /// - /// 获取状态优先级(用于状态冲突解决) - /// - /// UI状态 - /// 状态优先级(数值越大优先级越高) - public static int GetStatePriority(UIState state) - { - switch (state) - { - case UIState.Error: - return 100; // 错误状态最高优先级 - case UIState.Exporting: - return 80; // 导出操作高优先级 - case UIState.Loading: - return 70; // 加载操作高优先级 - case UIState.Animating: - return 60; // 动画播放中等优先级 - case UIState.Planning: - return 50; // 路径规划中等优先级 - case UIState.Updating: - return 40; // 更新操作中等优先级 - case UIState.Editing: - return 30; // 编辑操作较低优先级 - case UIState.Idle: - return 10; // 空闲状态最低优先级 - default: - return 0; - } - } - - /// - /// 判断状态是否为忙碌状态 - /// - /// UI状态 - /// 是否为忙碌状态 - public static bool IsStateStrictBusy(UIState state) - { - switch (state) - { - case UIState.Planning: - case UIState.Updating: - case UIState.Animating: - case UIState.Loading: - case UIState.Exporting: - return true; - case UIState.Idle: - case UIState.Editing: - case UIState.Error: - return false; - default: - return false; - } - } - - /// - /// 等待状态变为指定状态(异步) - /// - /// 目标状态 - /// 超时时间(毫秒) - /// 是否在超时前达到目标状态 - public async Task WaitForStateAsync(UIState targetState, int timeout = 30000) - { - var startTime = DateTime.UtcNow; - var timeoutSpan = TimeSpan.FromMilliseconds(timeout); - - while (CurrentState != targetState && DateTime.UtcNow - startTime < timeoutSpan) - { - await Task.Delay(100); // 每100ms检查一次 - } - - var success = CurrentState == targetState; - if (!success) - { - LogManager.Warning($"UIStateMachine等待状态超时: 目标状态={GetStateDescription(targetState)}, 当前状态={GetStateDescription(CurrentState)}"); - } - - return success; - } - - #endregion - - #region 事件处理 - - /// - /// 触发状态变更事件 - /// - /// 状态变更事件参数 - protected virtual void OnStateChanged(StateChangedEventArgs args) - { - try - { - // 使用UIStateManager确保在UI线程中触发事件 - if (_uiStateManager.IsUIThread) - { - StateChanged?.Invoke(this, args); - } - else - { - _uiStateManager.QueueUIUpdate(() => - { - try - { - StateChanged?.Invoke(this, args); - } - catch (Exception ex) - { - LogManager.Error($"UIStateMachine状态变更事件处理失败: {ex.Message}"); - } - }); - } - } - catch (Exception ex) - { - LogManager.Error($"UIStateMachine OnStateChanged异常: {ex.Message}"); - } - } - - /// - /// 触发状态转换前事件 - /// - /// 状态转换事件参数 - protected virtual void OnStateTransitioning(StateTransitionEventArgs args) - { - try - { - StateTransitioning?.Invoke(this, args); - } - catch (Exception ex) - { - LogManager.Error($"UIStateMachine OnStateTransitioning异常: {ex.Message}"); - } - } - - #endregion - - #region 释放资源 - - /// - /// 释放状态机资源 - /// - public void Dispose() - { - lock (_stateLock) - { - ClearStateHistory(); - StateChanged = null; - StateTransitioning = null; - - LogManager.Info("UIStateMachine已释放"); - } - } - - #endregion - } - - #region 枚举和事件参数类 - - /// - /// UI状态枚举 - /// - public enum UIState - { - /// - /// 空闲状态 - 无任何操作进行 - /// - Idle, - - /// - /// 路径规划状态 - 正在进行路径规划计算 - /// - Planning, - - /// - /// 更新状态 - 正在更新UI或数据 - /// - Updating, - - /// - /// 动画播放状态 - 正在播放路径动画 - /// - Animating, - - /// - /// 加载状态 - 正在加载模型或数据 - /// - Loading, - - /// - /// 导出状态 - 正在导出数据或模型 - /// - Exporting, - - /// - /// 编辑状态 - 正在编辑路径或参数 - /// - Editing, - - /// - /// 错误状态 - 发生错误需要处理 - /// - Error - } - - /// - /// 状态转换记录 - /// - public class StateTransitionRecord - { - /// - /// 源状态 - /// - public UIState FromState { get; set; } - - /// - /// 目标状态 - /// - public UIState ToState { get; set; } - - /// - /// 转换上下文信息 - /// - public string Context { get; set; } - - /// - /// 转换时间戳 - /// - public DateTime Timestamp { get; set; } - } - - /// - /// 状态变更事件参数 - /// - public class StateChangedEventArgs : EventArgs - { - /// - /// 前一个状态 - /// - public UIState PreviousState { get; } - - /// - /// 当前状态 - /// - public UIState CurrentState { get; } - - /// - /// 转换上下文信息 - /// - public string Context { get; } - - /// - /// 转换时间戳 - /// - public DateTime Timestamp { get; } - - public StateChangedEventArgs(UIState previousState, UIState currentState, string context) - { - PreviousState = previousState; - CurrentState = currentState; - Context = context ?? string.Empty; - Timestamp = DateTime.UtcNow; - } - } - - /// - /// 状态转换前事件参数 - /// - public class StateTransitionEventArgs : EventArgs - { - /// - /// 源状态 - /// - public UIState FromState { get; } - - /// - /// 目标状态 - /// - public UIState ToState { get; } - - /// - /// 转换上下文信息 - /// - public string Context { get; } - - /// - /// 是否取消转换 - /// - public bool Cancel { get; set; } = false; - - public StateTransitionEventArgs(UIState fromState, UIState toState, string context) - { - FromState = fromState; - ToState = toState; - Context = context ?? string.Empty; - } - } - - #endregion -} \ No newline at end of file