阶段一:删除冗余的UIStateMachine

- 删除 src/Core/UIStateMachine.cs
- UIStateMachine和UIState枚举完全未使用
- 项目实际使用PathEditState作为状态管理
- 编译验证通过,无任何错误

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
tian 2025-09-30 22:17:48 +08:00
parent 47ade72438
commit b048235657
3 changed files with 226 additions and 744 deletions

View File

@ -5,6 +5,7 @@
### [2025/09/29]
1. [x] (功能)导出导航地图为图片
2. [x] (功能)增加时间标签功能,以限速和路径段评估路径运行时间
### [2025/09/28]

View File

@ -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 # 回滚最后一次提交
```

View File

@ -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
{
/// <summary>
/// UI状态机 - 管理整个应用的UI状态转换
/// 提供线程安全的状态管理、状态转换验证和历史跟踪功能
/// 集成UIStateManager进行状态变更的UI通知
/// </summary>
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<StateTransitionRecord> _stateHistory = new List<StateTransitionRecord>();
private readonly int _maxHistoryRecords = 100; // 最大历史记录数
// 状态转换验证规则
private readonly Dictionary<UIState, HashSet<UIState>> _allowedTransitions;
// 状态变更事件
public event EventHandler<StateChangedEventArgs> StateChanged;
public event EventHandler<StateTransitionEventArgs> StateTransitioning;
/// <summary>
/// 获取UIStateMachine的单例实例
/// </summary>
public static UIStateMachine Instance
{
get
{
if (_instance == null)
{
lock (_instanceLock)
{
if (_instance == null)
{
_instance = new UIStateMachine();
}
}
}
return _instance;
}
}
/// <summary>
/// 获取当前UI状态线程安全
/// </summary>
public UIState CurrentState
{
get
{
lock (_stateLock)
{
return _currentState;
}
}
}
/// <summary>
/// 获取状态历史记录的快照
/// </summary>
public StateTransitionRecord[] StateHistory
{
get
{
lock (_stateLock)
{
return _stateHistory.ToArray();
}
}
}
/// <summary>
/// 获取当前状态描述
/// </summary>
public string CurrentStateDescription => GetStateDescription(CurrentState);
/// <summary>
/// 获取当前状态是否为忙碌状态
/// </summary>
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;
}
}
/// <summary>
/// 初始化状态转换规则
/// </summary>
/// <returns>状态转换规则字典</returns>
private Dictionary<UIState, HashSet<UIState>> InitializeStateTransitions()
{
var transitions = new Dictionary<UIState, HashSet<UIState>>();
// Idle状态可以转换到任何状态
transitions[UIState.Idle] = new HashSet<UIState>
{
UIState.Planning,
UIState.Updating,
UIState.Animating,
UIState.Error,
UIState.Loading,
UIState.Exporting,
UIState.Editing
};
// Planning状态的转换
transitions[UIState.Planning] = new HashSet<UIState>
{
UIState.Idle,
UIState.Updating,
UIState.Error,
UIState.Editing
};
// Updating状态的转换
transitions[UIState.Updating] = new HashSet<UIState>
{
UIState.Idle,
UIState.Planning,
UIState.Error,
UIState.Animating
};
// Animating状态的转换
transitions[UIState.Animating] = new HashSet<UIState>
{
UIState.Idle,
UIState.Updating,
UIState.Error
};
// Loading状态的转换
transitions[UIState.Loading] = new HashSet<UIState>
{
UIState.Idle,
UIState.Error,
UIState.Planning
};
// Exporting状态的转换
transitions[UIState.Exporting] = new HashSet<UIState>
{
UIState.Idle,
UIState.Error
};
// Editing状态的转换
transitions[UIState.Editing] = new HashSet<UIState>
{
UIState.Idle,
UIState.Planning,
UIState.Updating,
UIState.Error
};
// Error状态可以转换到Idle或回到任何正常状态
transitions[UIState.Error] = new HashSet<UIState>
{
UIState.Idle,
UIState.Planning,
UIState.Updating,
UIState.Animating,
UIState.Loading,
UIState.Exporting,
UIState.Editing
};
return transitions;
}
#endregion
#region
/// <summary>
/// 尝试转换状态(线程安全)
/// </summary>
/// <param name="newState">目标状态</param>
/// <param name="context">转换上下文信息</param>
/// <returns>转换是否成功</returns>
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);
}
/// <summary>
/// 强制转换状态(用于错误恢复)
/// </summary>
/// <param name="newState">目标状态</param>
/// <param name="context">转换上下文信息</param>
/// <returns>转换是否成功</returns>
public bool ForceTransition(UIState newState, string context = "强制转换")
{
var currentState = CurrentState;
LogManager.Warning($"UIStateMachine强制状态转换: {GetStateDescription(currentState)} -> {GetStateDescription(newState)}");
return ExecuteStateTransition(currentState, newState, context);
}
/// <summary>
/// 执行状态转换的核心逻辑
/// </summary>
/// <param name="fromState">源状态</param>
/// <param name="toState">目标状态</param>
/// <param name="context">转换上下文</param>
/// <returns>转换是否成功</returns>
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;
}
}
}
/// <summary>
/// 验证状态转换是否被允许
/// </summary>
/// <param name="fromState">源状态</param>
/// <param name="toState">目标状态</param>
/// <returns>转换是否被允许</returns>
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
/// <summary>
/// 记录状态转换历史
/// </summary>
/// <param name="fromState">源状态</param>
/// <param name="toState">目标状态</param>
/// <param name="context">转换上下文</param>
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);
}
}
/// <summary>
/// 获取指定时间范围内的状态历史
/// </summary>
/// <param name="since">起始时间</param>
/// <returns>状态转换记录数组</returns>
public StateTransitionRecord[] GetStateHistorySince(DateTime since)
{
lock (_stateLock)
{
return _stateHistory.Where(record => record.Timestamp >= since).ToArray();
}
}
/// <summary>
/// 获取最近的N条状态历史记录
/// </summary>
/// <param name="count">记录数量</param>
/// <returns>状态转换记录数组</returns>
public StateTransitionRecord[] GetRecentStateHistory(int count = 10)
{
lock (_stateLock)
{
var takeCount = Math.Min(count, _stateHistory.Count);
return _stateHistory.Skip(_stateHistory.Count - takeCount).ToArray();
}
}
/// <summary>
/// 清空状态历史记录
/// </summary>
public void ClearStateHistory()
{
lock (_stateLock)
{
_stateHistory.Clear();
LogManager.Info("UIStateMachine状态历史已清空");
}
}
#endregion
#region
/// <summary>
/// 回滚到上一个状态
/// </summary>
/// <returns>回滚是否成功</returns>
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;
}
}
/// <summary>
/// 回滚到指定状态
/// </summary>
/// <param name="targetState">目标状态</param>
/// <returns>回滚是否成功</returns>
public bool RollbackToState(UIState targetState)
{
return TryTransition(targetState, $"回滚到{GetStateDescription(targetState)}状态");
}
#endregion
#region
/// <summary>
/// 获取状态的中文描述
/// </summary>
/// <param name="state">UI状态</param>
/// <returns>状态描述</returns>
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 "未知状态";
}
}
/// <summary>
/// 获取状态优先级(用于状态冲突解决)
/// </summary>
/// <param name="state">UI状态</param>
/// <returns>状态优先级(数值越大优先级越高)</returns>
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;
}
}
/// <summary>
/// 判断状态是否为忙碌状态
/// </summary>
/// <param name="state">UI状态</param>
/// <returns>是否为忙碌状态</returns>
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;
}
}
/// <summary>
/// 等待状态变为指定状态(异步)
/// </summary>
/// <param name="targetState">目标状态</param>
/// <param name="timeout">超时时间(毫秒)</param>
/// <returns>是否在超时前达到目标状态</returns>
public async Task<bool> 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
/// <summary>
/// 触发状态变更事件
/// </summary>
/// <param name="args">状态变更事件参数</param>
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}");
}
}
/// <summary>
/// 触发状态转换前事件
/// </summary>
/// <param name="args">状态转换事件参数</param>
protected virtual void OnStateTransitioning(StateTransitionEventArgs args)
{
try
{
StateTransitioning?.Invoke(this, args);
}
catch (Exception ex)
{
LogManager.Error($"UIStateMachine OnStateTransitioning异常: {ex.Message}");
}
}
#endregion
#region
/// <summary>
/// 释放状态机资源
/// </summary>
public void Dispose()
{
lock (_stateLock)
{
ClearStateHistory();
StateChanged = null;
StateTransitioning = null;
LogManager.Info("UIStateMachine已释放");
}
}
#endregion
}
#region
/// <summary>
/// UI状态枚举
/// </summary>
public enum UIState
{
/// <summary>
/// 空闲状态 - 无任何操作进行
/// </summary>
Idle,
/// <summary>
/// 路径规划状态 - 正在进行路径规划计算
/// </summary>
Planning,
/// <summary>
/// 更新状态 - 正在更新UI或数据
/// </summary>
Updating,
/// <summary>
/// 动画播放状态 - 正在播放路径动画
/// </summary>
Animating,
/// <summary>
/// 加载状态 - 正在加载模型或数据
/// </summary>
Loading,
/// <summary>
/// 导出状态 - 正在导出数据或模型
/// </summary>
Exporting,
/// <summary>
/// 编辑状态 - 正在编辑路径或参数
/// </summary>
Editing,
/// <summary>
/// 错误状态 - 发生错误需要处理
/// </summary>
Error
}
/// <summary>
/// 状态转换记录
/// </summary>
public class StateTransitionRecord
{
/// <summary>
/// 源状态
/// </summary>
public UIState FromState { get; set; }
/// <summary>
/// 目标状态
/// </summary>
public UIState ToState { get; set; }
/// <summary>
/// 转换上下文信息
/// </summary>
public string Context { get; set; }
/// <summary>
/// 转换时间戳
/// </summary>
public DateTime Timestamp { get; set; }
}
/// <summary>
/// 状态变更事件参数
/// </summary>
public class StateChangedEventArgs : EventArgs
{
/// <summary>
/// 前一个状态
/// </summary>
public UIState PreviousState { get; }
/// <summary>
/// 当前状态
/// </summary>
public UIState CurrentState { get; }
/// <summary>
/// 转换上下文信息
/// </summary>
public string Context { get; }
/// <summary>
/// 转换时间戳
/// </summary>
public DateTime Timestamp { get; }
public StateChangedEventArgs(UIState previousState, UIState currentState, string context)
{
PreviousState = previousState;
CurrentState = currentState;
Context = context ?? string.Empty;
Timestamp = DateTime.UtcNow;
}
}
/// <summary>
/// 状态转换前事件参数
/// </summary>
public class StateTransitionEventArgs : EventArgs
{
/// <summary>
/// 源状态
/// </summary>
public UIState FromState { get; }
/// <summary>
/// 目标状态
/// </summary>
public UIState ToState { get; }
/// <summary>
/// 转换上下文信息
/// </summary>
public string Context { get; }
/// <summary>
/// 是否取消转换
/// </summary>
public bool Cancel { get; set; } = false;
public StateTransitionEventArgs(UIState fromState, UIState toState, string context)
{
FromState = fromState;
ToState = toState;
Context = context ?? string.Empty;
}
}
#endregion
}