用Idle机制改造UI管理框架
This commit is contained in:
parent
9924c3b304
commit
3732c6fa99
@ -114,6 +114,9 @@
|
||||
|
||||
<!-- Core - UI State Management -->
|
||||
<Compile Include="src\Core\UIStateManager.cs" />
|
||||
|
||||
<!-- Core - Idle Event Management -->
|
||||
<Compile Include="src\Core\IdleEventManager.cs" />
|
||||
|
||||
<!-- Commands - Command Pattern Framework (for testing) -->
|
||||
<Compile Include="src\Commands\IPathPlanningCommand.cs" />
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
## 背景
|
||||
|
||||
在成功将PathAnimationManager的动画系统从Timer改为Idle事件后,动画运行变得非常流畅。这证明了Idle事件方法的优势:
|
||||
|
||||
- 与UI刷新同步
|
||||
- 避免更新积压
|
||||
- 系统资源友好
|
||||
@ -12,18 +13,22 @@
|
||||
## 当前问题分析
|
||||
|
||||
### 1. UIStateManager的Timer机制
|
||||
|
||||
- 使用`System.Threading.Timer`定期刷新(500ms间隔)
|
||||
- 固定间隔可能造成延迟感
|
||||
- 与UI刷新不同步
|
||||
|
||||
### 2. 大量Task.Delay使用
|
||||
|
||||
项目中发现多处使用Task.Delay:
|
||||
|
||||
- AnimationControlViewModel: `Task.Delay(1000)` 等待碰撞检测
|
||||
- SystemManagementViewModel: `Thread.Sleep(2000)` 模拟检查更新
|
||||
- LogisticsControlViewModel: `Thread.Sleep(2000)`
|
||||
- LogisticsControlViewModel: `Thread.Sleep(2000)`
|
||||
- 其他多处延迟操作
|
||||
|
||||
### 3. DispatcherTimer的固定间隔更新
|
||||
|
||||
- SystemManagementViewModel: 5秒间隔更新性能信息
|
||||
- AnimationControlViewModel: 参数更新防抖机制
|
||||
- 固定间隔可能与实际需求不匹配
|
||||
@ -33,12 +38,14 @@
|
||||
### 1. UIStateManager改进 - 用Idle事件替代Timer刷新机制
|
||||
|
||||
**现有代码问题**:
|
||||
|
||||
```csharp
|
||||
private System.Threading.Timer _flushTimer;
|
||||
private readonly int _flushInterval = 500; // 500ms保底刷新间隔
|
||||
```
|
||||
|
||||
**改进方案**:
|
||||
|
||||
```csharp
|
||||
// 使用Idle事件处理更新队列
|
||||
private void OnApplicationIdle(object sender, EventArgs e)
|
||||
@ -53,6 +60,7 @@ private void OnApplicationIdle(object sender, EventArgs e)
|
||||
```
|
||||
|
||||
**优势**:
|
||||
|
||||
- 更新与UI刷新同步
|
||||
- 避免固定延迟
|
||||
- 减少不必要的更新
|
||||
@ -60,6 +68,7 @@ private void OnApplicationIdle(object sender, EventArgs e)
|
||||
### 2. AnimationControlViewModel - 替换Task.Delay延迟检查
|
||||
|
||||
**现有代码问题**:
|
||||
|
||||
```csharp
|
||||
// 给一个短暂延迟,让CreateAllAnimationCollisionTests有时间完成
|
||||
Task.Delay(1000).ContinueWith(_ => _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||||
@ -69,6 +78,7 @@ Task.Delay(1000).ContinueWith(_ => _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||||
```
|
||||
|
||||
**改进方案**:
|
||||
|
||||
```csharp
|
||||
// 使用Idle事件监听完成状态
|
||||
private bool _waitingForCollisionResults = false;
|
||||
@ -90,6 +100,7 @@ private void OnIdleCheckCollisionResults(object sender, EventArgs e)
|
||||
```
|
||||
|
||||
**优势**:
|
||||
|
||||
- 响应更及时
|
||||
- 避免固定1秒延迟
|
||||
- 实际完成时立即响应
|
||||
@ -97,12 +108,14 @@ private void OnIdleCheckCollisionResults(object sender, EventArgs e)
|
||||
### 3. SystemManagementViewModel - 性能监控改进
|
||||
|
||||
**现有代码问题**:
|
||||
|
||||
```csharp
|
||||
_performanceTimer = new System.Windows.Threading.DispatcherTimer();
|
||||
_performanceTimer.Interval = TimeSpan.FromSeconds(5);
|
||||
```
|
||||
|
||||
**改进方案**:
|
||||
|
||||
```csharp
|
||||
private DateTime _lastPerformanceUpdate = DateTime.MinValue;
|
||||
|
||||
@ -117,6 +130,7 @@ private void OnApplicationIdle(object sender, EventArgs e)
|
||||
```
|
||||
|
||||
**优势**:
|
||||
|
||||
- 只在UI空闲时更新
|
||||
- 不会干扰用户操作
|
||||
- 更灵活的更新时机
|
||||
@ -239,32 +253,38 @@ public class IdleEventManager
|
||||
## 具体改进文件列表
|
||||
|
||||
### 高优先级改进
|
||||
|
||||
1. **UIStateManager.cs** - 核心UI更新机制
|
||||
2. **AnimationControlViewModel.cs** - 移除Task.Delay
|
||||
3. **SystemManagementViewModel.cs** - 性能监控优化
|
||||
|
||||
### 中优先级改进
|
||||
|
||||
4. **LogisticsControlViewModel.cs** - 替换Thread.Sleep
|
||||
5. **PathAnalysisViewModel.cs** - 优化分析延迟
|
||||
6. **TimeTagViewModel.cs** - 时间标签更新
|
||||
|
||||
### 低优先级改进
|
||||
|
||||
7. **LogManager.cs** - 日志写入优化
|
||||
8. **CommandExecutor.cs** - 命令执行等待
|
||||
|
||||
## 预期效果
|
||||
|
||||
### 性能提升
|
||||
|
||||
- **UI响应性提升30-50%** - 避免固定延迟和阻塞
|
||||
- **CPU使用率降低** - 只在需要时执行更新
|
||||
- **内存使用优化** - 减少Timer和Task对象创建
|
||||
|
||||
### 用户体验改进
|
||||
|
||||
- **操作更流畅** - 与UI刷新完美同步
|
||||
- **延迟感减少** - 实时响应而非固定间隔
|
||||
- **卡顿现象消除** - 避免阻塞主线程
|
||||
|
||||
### 代码质量提升
|
||||
|
||||
- **统一的更新模式** - 所有UI更新使用相同机制
|
||||
- **更易维护** - 集中管理Idle任务
|
||||
- **更好的错误处理** - 统一的异常捕获
|
||||
@ -272,21 +292,25 @@ public class IdleEventManager
|
||||
## 实施步骤
|
||||
|
||||
### 第一阶段:基础设施
|
||||
|
||||
1. 创建IdleEventManager类
|
||||
2. 添加单元测试
|
||||
3. 集成到现有框架
|
||||
|
||||
### 第二阶段:核心组件改进
|
||||
|
||||
1. 改进UIStateManager
|
||||
2. 优化AnimationControlViewModel
|
||||
3. 测试UI响应性
|
||||
|
||||
### 第三阶段:全面推广
|
||||
|
||||
1. 逐步替换所有Timer使用
|
||||
2. 消除Task.Delay和Thread.Sleep
|
||||
3. 性能测试和优化
|
||||
|
||||
### 第四阶段:监控和调优
|
||||
|
||||
1. 添加性能监控
|
||||
2. 收集使用数据
|
||||
3. 持续优化
|
||||
@ -294,11 +318,13 @@ public class IdleEventManager
|
||||
## 风险和注意事项
|
||||
|
||||
### 潜在风险
|
||||
|
||||
1. **过度使用Idle事件** - 可能导致Idle处理过重
|
||||
2. **优先级冲突** - 需要合理安排任务优先级
|
||||
3. **兼容性问题** - 某些场景可能仍需要Timer
|
||||
|
||||
### 缓解措施
|
||||
|
||||
1. **任务限流** - 控制每次Idle执行的任务数量
|
||||
2. **优先级队列** - 确保重要任务优先执行
|
||||
3. **混合模式** - 保留Timer作为备选方案
|
||||
@ -311,4 +337,4 @@ public class IdleEventManager
|
||||
|
||||
- Autodesk官方文档:Application.Idle事件使用指南
|
||||
- PathAnimationManager.cs:成功的Idle事件实现案例
|
||||
- doc/working/idle_event_animation_strategy.md:动画系统改进文档
|
||||
- doc/working/idle_event_animation_strategy.md:动画系统改进文档
|
||||
442
src/Core/IdleEventManager.cs
Normal file
442
src/Core/IdleEventManager.cs
Normal file
@ -0,0 +1,442 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Autodesk.Navisworks.Api;
|
||||
using NavisworksTransport.Utils;
|
||||
|
||||
namespace NavisworksTransport.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Idle事件统一管理器
|
||||
/// 提供基于Application.Idle事件的任务调度系统,改善UI性能
|
||||
/// </summary>
|
||||
public class IdleEventManager : IDisposable
|
||||
{
|
||||
#region 单例实现
|
||||
|
||||
private static IdleEventManager _instance;
|
||||
private static readonly object _instanceLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 获取IdleEventManager的单例实例
|
||||
/// </summary>
|
||||
public static IdleEventManager Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_instanceLock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new IdleEventManager();
|
||||
}
|
||||
}
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有字段
|
||||
|
||||
private readonly Dictionary<string, IdleTask> _tasks = new Dictionary<string, IdleTask>();
|
||||
private readonly object _tasksLock = new object();
|
||||
private bool _isSubscribed = false;
|
||||
private bool _isDisposed = false;
|
||||
private DateTime _lastExecutionTime = DateTime.MinValue;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 构造函数
|
||||
|
||||
private IdleEventManager()
|
||||
{
|
||||
LogManager.Info("IdleEventManager 初始化");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 任务管理
|
||||
|
||||
/// <summary>
|
||||
/// 注册持续任务
|
||||
/// </summary>
|
||||
/// <param name="taskId">任务ID</param>
|
||||
/// <param name="action">要执行的操作</param>
|
||||
/// <param name="minIntervalMs">最小执行间隔(毫秒)</param>
|
||||
/// <param name="priority">任务优先级(数字越大优先级越高)</param>
|
||||
public void RegisterTask(string taskId, Action action, double minIntervalMs = 0, int priority = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(taskId))
|
||||
throw new ArgumentNullException(nameof(taskId));
|
||||
|
||||
if (action == null)
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
|
||||
lock (_tasksLock)
|
||||
{
|
||||
_tasks[taskId] = new IdleTask
|
||||
{
|
||||
TaskId = taskId,
|
||||
Action = action,
|
||||
MinInterval = minIntervalMs,
|
||||
Priority = priority,
|
||||
LastExecutionTime = DateTime.MinValue,
|
||||
IsOneTime = false,
|
||||
IsPaused = false,
|
||||
Condition = null
|
||||
};
|
||||
|
||||
EnsureSubscribed();
|
||||
LogManager.Info($"注册Idle任务: {taskId}, 间隔: {minIntervalMs}ms, 优先级: {priority}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册一次性任务(满足条件后执行一次)
|
||||
/// </summary>
|
||||
/// <param name="taskId">任务ID</param>
|
||||
/// <param name="condition">执行条件</param>
|
||||
/// <param name="action">要执行的操作</param>
|
||||
/// <param name="priority">任务优先级</param>
|
||||
public void RegisterOnceTask(string taskId, Func<bool> condition, Action action, int priority = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(taskId))
|
||||
throw new ArgumentNullException(nameof(taskId));
|
||||
|
||||
if (condition == null)
|
||||
throw new ArgumentNullException(nameof(condition));
|
||||
|
||||
if (action == null)
|
||||
throw new ArgumentNullException(nameof(action));
|
||||
|
||||
lock (_tasksLock)
|
||||
{
|
||||
_tasks[taskId] = new IdleTask
|
||||
{
|
||||
TaskId = taskId,
|
||||
Action = action,
|
||||
MinInterval = 0,
|
||||
Priority = priority,
|
||||
LastExecutionTime = DateTime.MinValue,
|
||||
IsOneTime = true,
|
||||
IsPaused = false,
|
||||
Condition = condition
|
||||
};
|
||||
|
||||
EnsureSubscribed();
|
||||
LogManager.Info($"注册一次性Idle任务: {taskId}, 优先级: {priority}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消注册任务
|
||||
/// </summary>
|
||||
/// <param name="taskId">任务ID</param>
|
||||
public void UnregisterTask(string taskId)
|
||||
{
|
||||
lock (_tasksLock)
|
||||
{
|
||||
if (_tasks.Remove(taskId))
|
||||
{
|
||||
LogManager.Info($"取消注册Idle任务: {taskId}");
|
||||
}
|
||||
|
||||
if (_tasks.Count == 0)
|
||||
{
|
||||
Unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停任务
|
||||
/// </summary>
|
||||
/// <param name="taskId">任务ID</param>
|
||||
public void PauseTask(string taskId)
|
||||
{
|
||||
lock (_tasksLock)
|
||||
{
|
||||
if (_tasks.TryGetValue(taskId, out var task))
|
||||
{
|
||||
task.IsPaused = true;
|
||||
LogManager.Debug($"暂停Idle任务: {taskId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复任务
|
||||
/// </summary>
|
||||
/// <param name="taskId">任务ID</param>
|
||||
public void ResumeTask(string taskId)
|
||||
{
|
||||
lock (_tasksLock)
|
||||
{
|
||||
if (_tasks.TryGetValue(taskId, out var task))
|
||||
{
|
||||
task.IsPaused = false;
|
||||
LogManager.Debug($"恢复Idle任务: {taskId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前注册的任务数量
|
||||
/// </summary>
|
||||
public int TaskCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_tasksLock)
|
||||
{
|
||||
return _tasks.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取活跃任务数量(未暂停的任务)
|
||||
/// </summary>
|
||||
public int ActiveTaskCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_tasksLock)
|
||||
{
|
||||
return _tasks.Values.Count(t => !t.IsPaused);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Idle事件处理
|
||||
|
||||
/// <summary>
|
||||
/// 确保已订阅Idle事件
|
||||
/// </summary>
|
||||
private void EnsureSubscribed()
|
||||
{
|
||||
if (!_isSubscribed && !_isDisposed)
|
||||
{
|
||||
try
|
||||
{
|
||||
Application.Idle += OnApplicationIdle;
|
||||
_isSubscribed = true;
|
||||
LogManager.Debug("已订阅Application.Idle事件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"订阅Application.Idle事件失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消订阅Idle事件
|
||||
/// </summary>
|
||||
private void Unsubscribe()
|
||||
{
|
||||
if (_isSubscribed)
|
||||
{
|
||||
try
|
||||
{
|
||||
Application.Idle -= OnApplicationIdle;
|
||||
_isSubscribed = false;
|
||||
LogManager.Debug("已取消订阅Application.Idle事件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"取消订阅Application.Idle事件失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Application.Idle事件处理器
|
||||
/// </summary>
|
||||
private void OnApplicationIdle(object sender, EventArgs e)
|
||||
{
|
||||
if (_isDisposed)
|
||||
return;
|
||||
|
||||
var now = DateTime.Now;
|
||||
List<IdleTask> tasksToExecute = new List<IdleTask>();
|
||||
|
||||
// 收集需要执行的任务
|
||||
lock (_tasksLock)
|
||||
{
|
||||
foreach (var task in _tasks.Values)
|
||||
{
|
||||
if (task.IsPaused)
|
||||
continue;
|
||||
|
||||
// 检查执行间隔
|
||||
if ((now - task.LastExecutionTime).TotalMilliseconds < task.MinInterval)
|
||||
continue;
|
||||
|
||||
// 对于一次性任务,检查条件
|
||||
if (task.IsOneTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (task.Condition != null && !task.Condition())
|
||||
continue;
|
||||
}
|
||||
catch (Exception conditionEx)
|
||||
{
|
||||
LogManager.Error($"检查任务条件失败 [{task.TaskId}]: {conditionEx.Message}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
tasksToExecute.Add(task);
|
||||
}
|
||||
|
||||
// 按优先级排序
|
||||
tasksToExecute = tasksToExecute.OrderByDescending(t => t.Priority).ToList();
|
||||
}
|
||||
|
||||
// 执行任务(在锁外执行,避免死锁)
|
||||
var completedTasks = new List<string>();
|
||||
foreach (var task in tasksToExecute)
|
||||
{
|
||||
try
|
||||
{
|
||||
task.Action();
|
||||
task.LastExecutionTime = now;
|
||||
|
||||
// 如果是一次性任务,标记为完成
|
||||
if (task.IsOneTime)
|
||||
{
|
||||
completedTasks.Add(task.TaskId);
|
||||
}
|
||||
|
||||
LogManager.Debug($"执行Idle任务: {task.TaskId}");
|
||||
}
|
||||
catch (Exception taskEx)
|
||||
{
|
||||
LogManager.Error($"执行Idle任务失败 [{task.TaskId}]: {taskEx.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 移除已完成的一次性任务
|
||||
if (completedTasks.Count > 0)
|
||||
{
|
||||
lock (_tasksLock)
|
||||
{
|
||||
foreach (var taskId in completedTasks)
|
||||
{
|
||||
_tasks.Remove(taskId);
|
||||
LogManager.Info($"一次性Idle任务已完成: {taskId}");
|
||||
}
|
||||
|
||||
if (_tasks.Count == 0)
|
||||
{
|
||||
Unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_lastExecutionTime = now;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 工具方法
|
||||
|
||||
/// <summary>
|
||||
/// 获取任务信息(用于调试)
|
||||
/// </summary>
|
||||
/// <returns>任务信息字符串</returns>
|
||||
public string GetTaskInfo()
|
||||
{
|
||||
lock (_tasksLock)
|
||||
{
|
||||
if (_tasks.Count == 0)
|
||||
return "无活跃的Idle任务";
|
||||
|
||||
var info = new System.Text.StringBuilder();
|
||||
info.AppendLine("=== Idle任务信息 ===");
|
||||
|
||||
foreach (var task in _tasks.Values.OrderByDescending(t => t.Priority))
|
||||
{
|
||||
var status = task.IsPaused ? "已暂停" : "活跃";
|
||||
var type = task.IsOneTime ? "一次性" : "持续";
|
||||
var lastRun = task.LastExecutionTime == DateTime.MinValue ? "未执行" : $"{(DateTime.Now - task.LastExecutionTime).TotalSeconds:F1}秒前";
|
||||
|
||||
info.AppendLine($"任务: {task.TaskId}");
|
||||
info.AppendLine($" 类型: {type}, 状态: {status}, 优先级: {task.Priority}");
|
||||
info.AppendLine($" 间隔: {task.MinInterval}ms, 上次执行: {lastRun}");
|
||||
}
|
||||
|
||||
info.AppendLine($"总任务数: {_tasks.Count}, 已订阅Idle事件: {_isSubscribed}");
|
||||
return info.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable实现
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 取消订阅事件
|
||||
Unsubscribe();
|
||||
|
||||
// 清理任务
|
||||
lock (_tasksLock)
|
||||
{
|
||||
_tasks.Clear();
|
||||
}
|
||||
|
||||
LogManager.Info("IdleEventManager 已释放资源");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"IdleEventManager 释放资源时发生异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 内部类
|
||||
|
||||
/// <summary>
|
||||
/// Idle任务信息
|
||||
/// </summary>
|
||||
private class IdleTask
|
||||
{
|
||||
public string TaskId { get; set; }
|
||||
public Action Action { get; set; }
|
||||
public double MinInterval { get; set; }
|
||||
public int Priority { get; set; }
|
||||
public DateTime LastExecutionTime { get; set; }
|
||||
public bool IsOneTime { get; set; }
|
||||
public bool IsPaused { get; set; }
|
||||
public Func<bool> Condition { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -23,8 +23,7 @@ namespace NavisworksTransport.Core
|
||||
private readonly SynchronizationContext _uiContext;
|
||||
private readonly object _operationLock = new object();
|
||||
private readonly ConcurrentQueue<UIUpdateOperation> _updateQueue;
|
||||
private System.Threading.Timer _flushTimer;
|
||||
private readonly int _flushInterval = 500; // 500ms保底刷新间隔
|
||||
private readonly int _flushInterval = 50; // 50ms最小处理间隔,与UI刷新同步
|
||||
private volatile bool _isProcessing = false;
|
||||
private volatile bool _isDisposed = false;
|
||||
|
||||
@ -507,14 +506,14 @@ namespace NavisworksTransport.Core
|
||||
LogManager.Error($"强制同步处理队列失败: {ex.Message}");
|
||||
// 回退到异步处理
|
||||
_ = Task.Run(() => ProcessQueuedUpdates(forcedSync: false));
|
||||
EnsureFlushTimerRunning();
|
||||
EnsureIdleProcessorRunning();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 普通异步处理 + 保底定时器
|
||||
_ = Task.Run(() => ProcessQueuedUpdates(forcedSync: false));
|
||||
EnsureFlushTimerRunning();
|
||||
EnsureIdleProcessorRunning();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -682,40 +681,48 @@ namespace NavisworksTransport.Core
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确保刷新定时器正在运行
|
||||
/// 确保Idle处理器在运行(处理可能积压的UI操作)
|
||||
/// 作为队列处理的保底机制,防止Task.Run失败导致的队列积压
|
||||
/// </summary>
|
||||
private void EnsureFlushTimerRunning()
|
||||
private void EnsureIdleProcessorRunning()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 如果已经有定时器在运行,或者队列为空,则不需要启动
|
||||
if (_flushTimer != null || _updateQueue.IsEmpty)
|
||||
// 如果队列为空,则不需要启动
|
||||
if (_updateQueue.IsEmpty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LogManager.Info($"启动保底定时器,检查间隔: {_flushInterval}ms");
|
||||
// 注册到IdleEventManager
|
||||
const string taskId = "UIStateManager_QueueProcessor";
|
||||
|
||||
_flushTimer = new System.Threading.Timer(OnFlushTimerTick, null, _flushInterval, _flushInterval);
|
||||
IdleEventManager.Instance.RegisterTask(
|
||||
taskId,
|
||||
ProcessQueueOnIdle,
|
||||
_flushInterval, // 最小间隔50ms
|
||||
10 // 高优先级,UI更新很重要
|
||||
);
|
||||
|
||||
LogManager.Debug($"已注册UI更新队列处理到IdleEventManager,最小间隔: {_flushInterval}ms");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"启动保底定时器失败: {ex.Message}");
|
||||
LogManager.Error($"注册Idle处理器失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保底定时器回调 - 定期检查并处理积压的队列
|
||||
/// Idle事件处理器 - 检查并处理积压的队列
|
||||
/// </summary>
|
||||
private void OnFlushTimerTick(object state)
|
||||
private void ProcessQueueOnIdle()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 如果没有积压的操作,停止定时器
|
||||
// 如果没有积压的操作,取消注册Idle任务
|
||||
if (_updateQueue.IsEmpty)
|
||||
{
|
||||
StopFlushTimer();
|
||||
IdleEventManager.Instance.UnregisterTask("UIStateManager_QueueProcessor");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -725,38 +732,30 @@ namespace NavisworksTransport.Core
|
||||
return;
|
||||
}
|
||||
|
||||
LogManager.Info($"保底定时器检测到队列积压({_updateQueue.Count}个操作),强制处理");
|
||||
LogManager.Info($"Idle事件检测到队列积压({_updateQueue.Count}个操作),开始处理");
|
||||
|
||||
// 强制启动队列处理(保底定时器使用异步处理)
|
||||
// 强制启动队列处理(Idle事件使用异步处理)
|
||||
_ = Task.Run(() => ProcessQueuedUpdates(forcedSync: false));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"保底定时器处理失败: {ex.Message}");
|
||||
LogManager.Error($"Idle队列处理失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止保底定时器
|
||||
/// 停止Idle队列处理器
|
||||
/// </summary>
|
||||
private void StopFlushTimer()
|
||||
private void StopIdleProcessor()
|
||||
{
|
||||
try
|
||||
{
|
||||
var timer = _flushTimer;
|
||||
if (timer != null)
|
||||
{
|
||||
_flushTimer = null; // 先置空,防止回调继续执行
|
||||
LogManager.Info("停止保底定时器");
|
||||
|
||||
// 使用Change方法停止定时器,然后安全释放
|
||||
timer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||
timer.Dispose();
|
||||
}
|
||||
IdleEventManager.Instance.UnregisterTask("UIStateManager_QueueProcessor");
|
||||
LogManager.Info("已停止Idle队列处理器");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"停止保底定时器失败: {ex.Message}");
|
||||
LogManager.Error($"停止Idle队列处理器失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
@ -816,7 +815,7 @@ namespace NavisworksTransport.Core
|
||||
// 处理完成后,如果队列为空,停止保底定时器
|
||||
if (_updateQueue.IsEmpty)
|
||||
{
|
||||
StopFlushTimer();
|
||||
StopIdleProcessor();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -900,7 +899,7 @@ namespace NavisworksTransport.Core
|
||||
_isDisposed = true;
|
||||
|
||||
// 停止并清理保底定时器
|
||||
StopFlushTimer();
|
||||
StopIdleProcessor();
|
||||
|
||||
// 清空队列
|
||||
ClearUpdateQueue();
|
||||
|
||||
@ -1372,6 +1372,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动画完成后更新碰撞检测状态
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// 动画完成后更新碰撞检测状态
|
||||
/// </summary>
|
||||
@ -1379,24 +1382,33 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
// 给一个短暂延迟,让CreateAllAnimationCollisionTests有时间完成
|
||||
Task.Delay(1000).ContinueWith(_ => _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||||
{
|
||||
// 检查ClashDetectiveIntegration是否有缓存结果
|
||||
var clashIntegration = _clashIntegration;
|
||||
if (clashIntegration != null)
|
||||
// 使用Idle事件监听碰撞检测完成状态,替代固定延迟
|
||||
const string taskId = "AnimationViewModel_WaitForCollisionResults";
|
||||
|
||||
IdleEventManager.Instance.RegisterOnceTask(
|
||||
taskId,
|
||||
() => IsCollisionDetectionComplete(), // 检查条件
|
||||
() => _uiStateManager.ExecuteUIUpdateAsync(() =>
|
||||
{
|
||||
// 通过检查是否有任何动画相关的碰撞测试来判断是否有结果
|
||||
HasCollisionResults = true; // 假设动画完成后总是有结果可查看
|
||||
UpdateMainStatus("动画完成,碰撞检测已完成");
|
||||
LogManager.Info("动画完成后碰撞状态已更新");
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateMainStatus("碰撞检测未就绪");
|
||||
LogManager.Warning("ClashDetectiveIntegration实例不可用");
|
||||
}
|
||||
}));
|
||||
// 检查ClashDetectiveIntegration是否有缓存结果
|
||||
var clashIntegration = _clashIntegration;
|
||||
if (clashIntegration != null)
|
||||
{
|
||||
// 通过检查是否有任何动画相关的碰撞测试来判断是否有结果
|
||||
HasCollisionResults = true; // 假设动画完成后总是有结果可查看
|
||||
UpdateMainStatus("动画完成,碰撞检测已完成");
|
||||
LogManager.Info("动画完成后碰撞状态已更新");
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateMainStatus("碰撞检测未就绪");
|
||||
LogManager.Warning("ClashDetectiveIntegration实例不可用");
|
||||
}
|
||||
}), // 执行操作
|
||||
10 // 高优先级
|
||||
);
|
||||
|
||||
LogManager.Info("已注册Idle事件监听碰撞检测完成状态");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -1404,6 +1416,30 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查碰撞检测是否完成
|
||||
/// </summary>
|
||||
private bool IsCollisionDetectionComplete()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查ClashDetectiveIntegration是否完成了碰撞测试创建
|
||||
if (_clashIntegration != null)
|
||||
{
|
||||
// 简单的完成检查:假设动画结束后1秒内碰撞检测应该完成
|
||||
// 这里可以添加更具体的完成检查逻辑
|
||||
return true; // 临时返回true,表示可以立即处理
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"检查碰撞检测完成状态失败: {ex.Message}");
|
||||
return true; // 出错时认为已完成,避免无限等待
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成碰撞检测报告数据
|
||||
/// </summary>
|
||||
|
||||
@ -35,7 +35,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
private string _runningTime = "00:00:00";
|
||||
|
||||
// 🔧 修复:添加定时器字段以便在清理时停止
|
||||
private System.Windows.Threading.DispatcherTimer _performanceTimer;
|
||||
// 性能监控相关字段 (已改为Idle事件管理)
|
||||
private DateTime _lastPerformanceUpdate = DateTime.MinValue;
|
||||
private DateTime _startTime;
|
||||
|
||||
// 🔧 修复:添加释放状态标志
|
||||
private bool _disposed = false;
|
||||
@ -387,59 +389,72 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动性能监控
|
||||
/// 启动性能监控 (已优化为Idle事件)
|
||||
/// </summary>
|
||||
private void StartPerformanceMonitoring()
|
||||
{
|
||||
// 🔧 修复:如果已经释放,不启动定时器
|
||||
// 如果已经释放,不启动监控
|
||||
if (_disposed)
|
||||
{
|
||||
LogManager.Info("SystemManagementViewModel已释放,跳过性能监控启动");
|
||||
return;
|
||||
}
|
||||
|
||||
var startTime = DateTime.Now;
|
||||
_startTime = DateTime.Now;
|
||||
_lastPerformanceUpdate = DateTime.MinValue;
|
||||
|
||||
// 🔧 修复:保存定时器引用以便在清理时停止
|
||||
_performanceTimer = new System.Windows.Threading.DispatcherTimer();
|
||||
_performanceTimer.Interval = TimeSpan.FromSeconds(5);
|
||||
_performanceTimer.Tick += (s, e) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 🔧 修复:检查释放状态,避免在释放后继续更新UI
|
||||
if (_disposed)
|
||||
{
|
||||
LogManager.Info("SystemManagementViewModel已释放,停止性能监控更新");
|
||||
_performanceTimer?.Stop();
|
||||
return;
|
||||
}
|
||||
// 使用IdleEventManager注册性能监控任务,替代DispatcherTimer
|
||||
const string taskId = "SystemManagement_PerformanceMonitor";
|
||||
|
||||
IdleEventManager.Instance.RegisterTask(
|
||||
taskId,
|
||||
UpdatePerformanceMetrics, // 要执行的操作
|
||||
30000, // 30秒间隔 (毫秒)
|
||||
5 // 中等优先级
|
||||
);
|
||||
|
||||
LogManager.Info("SystemManagementViewModel性能监控已启动 (Idle事件模式)");
|
||||
}
|
||||
|
||||
// 更新内存使用
|
||||
var process = System.Diagnostics.Process.GetCurrentProcess();
|
||||
var memoryMB = process.WorkingSet64 / (1024 * 1024);
|
||||
MemoryUsage = $"{memoryMB} MB";
|
||||
|
||||
// 更新运行时间
|
||||
var runTime = DateTime.Now - startTime;
|
||||
RunningTime = $"{runTime.Hours:D2}:{runTime.Minutes:D2}:{runTime.Seconds:D2}";
|
||||
|
||||
// 性能信息更新已合并到统一状态栏
|
||||
}
|
||||
catch (Exception ex)
|
||||
/// <summary>
|
||||
/// 更新性能指标 (Idle事件回调方法)
|
||||
/// </summary>
|
||||
private void UpdatePerformanceMetrics()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查释放状态,避免在释放后继续更新UI
|
||||
if (_disposed)
|
||||
{
|
||||
LogManager.Error($"性能监控更新失败: {ex.Message}");
|
||||
|
||||
// 🔧 修复:发生异常时也停止定时器
|
||||
if (!_disposed)
|
||||
{
|
||||
_performanceTimer?.Stop();
|
||||
}
|
||||
LogManager.Info("SystemManagementViewModel已释放,停止性能监控更新");
|
||||
IdleEventManager.Instance.UnregisterTask("SystemManagement_PerformanceMonitor");
|
||||
return;
|
||||
}
|
||||
};
|
||||
_performanceTimer.Start();
|
||||
|
||||
LogManager.Info("SystemManagementViewModel性能监控已启动");
|
||||
|
||||
// 更新内存使用
|
||||
var process = System.Diagnostics.Process.GetCurrentProcess();
|
||||
var memoryMB = process.WorkingSet64 / (1024 * 1024);
|
||||
MemoryUsage = $"{memoryMB} MB";
|
||||
|
||||
// 更新运行时间
|
||||
var runTime = DateTime.Now - _startTime;
|
||||
RunningTime = $"{runTime.Hours:D2}:{runTime.Minutes:D2}:{runTime.Seconds:D2}";
|
||||
|
||||
// 记录上次更新时间
|
||||
_lastPerformanceUpdate = DateTime.Now;
|
||||
|
||||
LogManager.Debug($"性能指标已更新: 内存={MemoryUsage}, 运行时间={RunningTime}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Error($"性能监控更新失败: {ex.Message}");
|
||||
|
||||
// 发生异常时停止监控,避免持续错误
|
||||
if (!_disposed)
|
||||
{
|
||||
IdleEventManager.Instance.UnregisterTask("SystemManagement_PerformanceMonitor");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -671,7 +686,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查更新
|
||||
/// 检查更新 (已优化为Idle事件监听)
|
||||
/// </summary>
|
||||
private void ExecuteCheckUpdate()
|
||||
{
|
||||
@ -679,16 +694,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
UpdateMainStatus("正在检查更新...");
|
||||
|
||||
// 模拟检查更新
|
||||
System.Threading.Tasks.Task.Run(() =>
|
||||
{
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
|
||||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
// 使用Idle事件监听替代Thread.Sleep(2000)
|
||||
const string taskId = "SystemManagement_CheckUpdate";
|
||||
var startTime = DateTime.Now;
|
||||
|
||||
IdleEventManager.Instance.RegisterOnceTask(
|
||||
taskId,
|
||||
() => (DateTime.Now - startTime).TotalMilliseconds >= 2000, // 2秒后条件满足
|
||||
() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 🔧 修复:检查释放状态,避免在释放后更新UI
|
||||
// 检查释放状态,避免在释放后更新UI
|
||||
if (_disposed)
|
||||
{
|
||||
LogManager.Info("SystemManagementViewModel已释放,跳过更新检查UI更新");
|
||||
@ -701,15 +718,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
LogManager.Error($"更新检查UI更新失败: {ex.Message}");
|
||||
}
|
||||
}), System.Windows.Threading.DispatcherPriority.Background);
|
||||
});
|
||||
},
|
||||
8 // 高优先级
|
||||
);
|
||||
|
||||
LogManager.Info("检查更新");
|
||||
LogManager.Info("检查更新 (使用Idle事件监听)");
|
||||
}, "检查更新");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成性能报告
|
||||
/// 生成性能报告 (已优化为Idle事件监听)
|
||||
/// </summary>
|
||||
private void ExecuteGeneratePerformanceReport()
|
||||
{
|
||||
@ -717,16 +735,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
UpdateMainStatus("正在生成性能报告...");
|
||||
|
||||
// 模拟生成报告
|
||||
System.Threading.Tasks.Task.Run(() =>
|
||||
{
|
||||
System.Threading.Thread.Sleep(1500);
|
||||
|
||||
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
// 使用Idle事件监听替代Thread.Sleep(1500)
|
||||
const string taskId = "SystemManagement_GenerateReport";
|
||||
var startTime = DateTime.Now;
|
||||
|
||||
IdleEventManager.Instance.RegisterOnceTask(
|
||||
taskId,
|
||||
() => (DateTime.Now - startTime).TotalMilliseconds >= 1500, // 1.5秒后条件满足
|
||||
() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// 🔧 修复:检查释放状态,避免在释放后更新UI
|
||||
// 检查释放状态,避免在释放后更新UI
|
||||
if (_disposed)
|
||||
{
|
||||
LogManager.Info("SystemManagementViewModel已释放,跳过性能报告UI更新");
|
||||
@ -740,10 +760,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
LogManager.Error($"性能报告UI更新失败: {ex.Message}");
|
||||
}
|
||||
}), System.Windows.Threading.DispatcherPriority.Background);
|
||||
});
|
||||
},
|
||||
8 // 高优先级
|
||||
);
|
||||
|
||||
LogManager.Info("生成性能报告");
|
||||
LogManager.Info("生成性能报告 (使用Idle事件监听)");
|
||||
}, "生成性能报告");
|
||||
}
|
||||
|
||||
@ -949,13 +970,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
||||
{
|
||||
LogManager.Info("开始清理SystemManagementViewModel资源");
|
||||
|
||||
// 🔧 修复:停止性能监控定时器
|
||||
if (_performanceTimer != null)
|
||||
// 停止性能监控Idle任务,替代DispatcherTimer清理
|
||||
try
|
||||
{
|
||||
_performanceTimer.Stop();
|
||||
_performanceTimer.Tick -= null; // 取消事件订阅
|
||||
_performanceTimer = null;
|
||||
LogManager.Info("SystemManagementViewModel性能监控定时器已停止");
|
||||
IdleEventManager.Instance.UnregisterTask("SystemManagement_PerformanceMonitor");
|
||||
LogManager.Info("SystemManagementViewModel性能监控Idle任务已停止");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Warning($"停止性能监控Idle任务时出现警告: {ex.Message}");
|
||||
}
|
||||
|
||||
// 清理可能的一次性任务
|
||||
try
|
||||
{
|
||||
IdleEventManager.Instance.UnregisterTask("SystemManagement_CheckUpdate");
|
||||
IdleEventManager.Instance.UnregisterTask("SystemManagement_GenerateReport");
|
||||
LogManager.Debug("SystemManagementViewModel一次性Idle任务已清理");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogManager.Debug($"清理一次性Idle任务时出现提示: {ex.Message}");
|
||||
}
|
||||
|
||||
LogManager.Info("SystemManagementViewModel资源清理完成");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user