阶段一:删除冗余的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:
parent
47ade72438
commit
b048235657
@ -5,6 +5,7 @@
|
|||||||
### [2025/09/29]
|
### [2025/09/29]
|
||||||
|
|
||||||
1. [x] (功能)导出导航地图为图片
|
1. [x] (功能)导出导航地图为图片
|
||||||
|
2. [x] (功能)增加时间标签功能,以限速和路径段评估路径运行时间
|
||||||
|
|
||||||
### [2025/09/28]
|
### [2025/09/28]
|
||||||
|
|
||||||
|
|||||||
225
doc/working/code_cleanup_plan.md
Normal file
225
doc/working/code_cleanup_plan.md
Normal 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 # 回滚最后一次提交
|
||||||
|
```
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user