diff --git a/NavisworksTransportPlugin.csproj b/NavisworksTransportPlugin.csproj index e5ad1a8..98fdac0 100644 --- a/NavisworksTransportPlugin.csproj +++ b/NavisworksTransportPlugin.csproj @@ -114,6 +114,9 @@ + + + diff --git a/doc/working/idle_event_animation_strategy.md b/doc/working/idle_event_animation_strategy_20250908.md similarity index 100% rename from doc/working/idle_event_animation_strategy.md rename to doc/working/idle_event_animation_strategy_20250908.md diff --git a/doc/working/idle_event_ui_improvement_strategy.md b/doc/working/idle_event_ui_improvement_strategy_20250908.md similarity index 99% rename from doc/working/idle_event_ui_improvement_strategy.md rename to doc/working/idle_event_ui_improvement_strategy_20250908.md index 63c762a..5cc77e6 100644 --- a/doc/working/idle_event_ui_improvement_strategy.md +++ b/doc/working/idle_event_ui_improvement_strategy_20250908.md @@ -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:动画系统改进文档 \ No newline at end of file +- doc/working/idle_event_animation_strategy.md:动画系统改进文档 diff --git a/src/Core/IdleEventManager.cs b/src/Core/IdleEventManager.cs new file mode 100644 index 0000000..a8860d8 --- /dev/null +++ b/src/Core/IdleEventManager.cs @@ -0,0 +1,442 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Autodesk.Navisworks.Api; +using NavisworksTransport.Utils; + +namespace NavisworksTransport.Core +{ + /// + /// Idle事件统一管理器 + /// 提供基于Application.Idle事件的任务调度系统,改善UI性能 + /// + public class IdleEventManager : IDisposable + { + #region 单例实现 + + private static IdleEventManager _instance; + private static readonly object _instanceLock = new object(); + + /// + /// 获取IdleEventManager的单例实例 + /// + public static IdleEventManager Instance + { + get + { + if (_instance == null) + { + lock (_instanceLock) + { + if (_instance == null) + { + _instance = new IdleEventManager(); + } + } + } + return _instance; + } + } + + #endregion + + #region 私有字段 + + private readonly Dictionary _tasks = new Dictionary(); + 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 任务管理 + + /// + /// 注册持续任务 + /// + /// 任务ID + /// 要执行的操作 + /// 最小执行间隔(毫秒) + /// 任务优先级(数字越大优先级越高) + 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}"); + } + } + + /// + /// 注册一次性任务(满足条件后执行一次) + /// + /// 任务ID + /// 执行条件 + /// 要执行的操作 + /// 任务优先级 + public void RegisterOnceTask(string taskId, Func 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}"); + } + } + + /// + /// 取消注册任务 + /// + /// 任务ID + public void UnregisterTask(string taskId) + { + lock (_tasksLock) + { + if (_tasks.Remove(taskId)) + { + LogManager.Info($"取消注册Idle任务: {taskId}"); + } + + if (_tasks.Count == 0) + { + Unsubscribe(); + } + } + } + + /// + /// 暂停任务 + /// + /// 任务ID + public void PauseTask(string taskId) + { + lock (_tasksLock) + { + if (_tasks.TryGetValue(taskId, out var task)) + { + task.IsPaused = true; + LogManager.Debug($"暂停Idle任务: {taskId}"); + } + } + } + + /// + /// 恢复任务 + /// + /// 任务ID + public void ResumeTask(string taskId) + { + lock (_tasksLock) + { + if (_tasks.TryGetValue(taskId, out var task)) + { + task.IsPaused = false; + LogManager.Debug($"恢复Idle任务: {taskId}"); + } + } + } + + /// + /// 获取当前注册的任务数量 + /// + public int TaskCount + { + get + { + lock (_tasksLock) + { + return _tasks.Count; + } + } + } + + /// + /// 获取活跃任务数量(未暂停的任务) + /// + public int ActiveTaskCount + { + get + { + lock (_tasksLock) + { + return _tasks.Values.Count(t => !t.IsPaused); + } + } + } + + #endregion + + #region Idle事件处理 + + /// + /// 确保已订阅Idle事件 + /// + 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}"); + } + } + } + + /// + /// 取消订阅Idle事件 + /// + private void Unsubscribe() + { + if (_isSubscribed) + { + try + { + Application.Idle -= OnApplicationIdle; + _isSubscribed = false; + LogManager.Debug("已取消订阅Application.Idle事件"); + } + catch (Exception ex) + { + LogManager.Error($"取消订阅Application.Idle事件失败: {ex.Message}"); + } + } + } + + /// + /// Application.Idle事件处理器 + /// + private void OnApplicationIdle(object sender, EventArgs e) + { + if (_isDisposed) + return; + + var now = DateTime.Now; + List tasksToExecute = new List(); + + // 收集需要执行的任务 + 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(); + 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 工具方法 + + /// + /// 获取任务信息(用于调试) + /// + /// 任务信息字符串 + 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 内部类 + + /// + /// Idle任务信息 + /// + 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 Condition { get; set; } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Core/UIStateManager.cs b/src/Core/UIStateManager.cs index 8c9832f..658fb57 100644 --- a/src/Core/UIStateManager.cs +++ b/src/Core/UIStateManager.cs @@ -23,8 +23,7 @@ namespace NavisworksTransport.Core private readonly SynchronizationContext _uiContext; private readonly object _operationLock = new object(); private readonly ConcurrentQueue _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 } /// - /// 确保刷新定时器正在运行 + /// 确保Idle处理器在运行(处理可能积压的UI操作) /// 作为队列处理的保底机制,防止Task.Run失败导致的队列积压 /// - 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}"); } } /// - /// 保底定时器回调 - 定期检查并处理积压的队列 + /// Idle事件处理器 - 检查并处理积压的队列 /// - 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}"); } } /// - /// 停止保底定时器 + /// 停止Idle队列处理器 /// - 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(); diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 8633278..948185d 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -1372,6 +1372,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + /// + /// 动画完成后更新碰撞检测状态 + /// /// /// 动画完成后更新碰撞检测状态 /// @@ -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 } } + /// + /// 检查碰撞检测是否完成 + /// + private bool IsCollisionDetectionComplete() + { + try + { + // 检查ClashDetectiveIntegration是否完成了碰撞测试创建 + if (_clashIntegration != null) + { + // 简单的完成检查:假设动画结束后1秒内碰撞检测应该完成 + // 这里可以添加更具体的完成检查逻辑 + return true; // 临时返回true,表示可以立即处理 + } + + return false; + } + catch (Exception ex) + { + LogManager.Error($"检查碰撞检测完成状态失败: {ex.Message}"); + return true; // 出错时认为已完成,避免无限等待 + } + } + /// /// 生成碰撞检测报告数据 /// diff --git a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs index d0dc664..65e42e1 100644 --- a/src/UI/WPF/ViewModels/SystemManagementViewModel.cs +++ b/src/UI/WPF/ViewModels/SystemManagementViewModel.cs @@ -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 } /// - /// 启动性能监控 + /// 启动性能监控 (已优化为Idle事件) /// 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) + /// + /// 更新性能指标 (Idle事件回调方法) + /// + 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 } /// - /// 检查更新 + /// 检查更新 (已优化为Idle事件监听) /// 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事件监听)"); }, "检查更新"); } /// - /// 生成性能报告 + /// 生成性能报告 (已优化为Idle事件监听) /// 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资源清理完成");