From 1b95c37b80e53afacccd63ea82e2b46e740b7c5a Mon Sep 17 00:00:00 2001
From: tian <11429339@qq.com>
Date: Thu, 18 Sep 2025 22:49:06 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=A2=B0=E6=92=9E=E6=A3=80?=
=?UTF-8?q?=E6=B5=8B=E6=8A=A5=E5=91=8A=E5=88=B0=E2=80=9C=E6=9F=A5=E7=9C=8B?=
=?UTF-8?q?=E7=A2=B0=E6=92=9E=E6=8A=A5=E5=91=8A=E2=80=9D=E6=97=B6=EF=BC=8C?=
=?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BC=82=E6=AD=A5=E7=94=9F=E6=88=90=E6=8A=A5?=
=?UTF-8?q?=E5=91=8A=E4=BA=A7=E7=94=9F=E7=9A=84=E5=B4=A9=E6=BA=83=E9=A3=8E?=
=?UTF-8?q?=E9=99=A9=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Commands/ViewCollisionReportCommand.cs | 199 ++++++++++++++----
.../ViewModels/AnimationControlViewModel.cs | 102 ++-------
.../WPF/Views/CollisionReportDialog.xaml.cs | 113 ++++++++--
3 files changed, 277 insertions(+), 137 deletions(-)
diff --git a/src/Commands/ViewCollisionReportCommand.cs b/src/Commands/ViewCollisionReportCommand.cs
index 0aa68cb..6ff06d9 100644
--- a/src/Commands/ViewCollisionReportCommand.cs
+++ b/src/Commands/ViewCollisionReportCommand.cs
@@ -91,6 +91,20 @@ namespace NavisworksTransport.Commands
///
public class ViewCollisionReportCommand : CommandBase
{
+ #region 静态缓存机制
+
+ ///
+ /// 碰撞报告结果缓存 - 使用测试名称作为键
+ ///
+ private static readonly Dictionary _reportCache = new Dictionary();
+
+ ///
+ /// 缓存操作锁对象
+ ///
+ private static readonly object _cacheLock = new object();
+
+ #endregion
+
private readonly CollisionReportParameters _parameters;
public ViewCollisionReportCommand(CollisionReportParameters parameters = null)
@@ -110,62 +124,101 @@ namespace NavisworksTransport.Commands
UpdateProgress(10, "开始生成碰撞报告...");
+ // 检查缓存
+ var testNameKey = GetLatestTestNameForCache();
+ if (!string.IsNullOrEmpty(testNameKey))
+ {
+ lock (_cacheLock)
+ {
+ if (_reportCache.ContainsKey(testNameKey))
+ {
+ var cachedResult = _reportCache[testNameKey];
+ LogManager.Info($"使用缓存的碰撞报告: {testNameKey}");
+
+ UpdateProgress(100, "使用缓存报告");
+
+ // 显示缓存的报告
+ ShowReport(cachedResult);
+
+ var cachedMessage = cachedResult.TotalCollisions > 0 ?
+ $"碰撞报告显示完成(缓存):发现 {cachedResult.TotalCollisions} 个碰撞" :
+ "碰撞报告显示完成(缓存):未发现碰撞";
+
+ return PathPlanningResult.Success(cachedResult, cachedMessage);
+ }
+ else
+ {
+ LogManager.Info($"未找到缓存报告,开始生成新报告: {testNameKey}");
+ }
+ }
+ }
+ else
+ {
+ LogManager.Warning("无法获取测试名称,跳过缓存检查");
+ }
+
var result = new CollisionReportResult();
try
{
- await Task.Run(() =>
+ UpdateProgress(30, "收集碰撞数据...");
+
+ // 收集所有碰撞数据及统计信息(同步执行,避免 COM 线程问题)
+ var collisionData = CollectAllCollisionData();
+ result.AllCollisions = collisionData.AllCollisions;
+
+ // 修改统计数据
+ var clashIntegration = ClashDetectiveIntegration.Instance;
+ result.AnimationCollisions = clashIntegration?.AnimationCollisionCount ?? 0; // 检测点数量
+ result.TotalCollisions = collisionData.ClashDetectiveCollisionCount;
+ result.MovingObjectInfo = collisionData.MovingObjectInfo;
+
+ // 新增:被撞物体清单
+ result.CollidedObjectsList = collisionData.UniqueCollidedObjects.OrderBy(x => x).ToList();
+ result.UniqueCollidedObjectsCount = collisionData.UniqueCollidedObjects.Count;
+
+ LogManager.Info($"碰撞报告计数 - 检查点: {result.AnimationCollisions}, Clash Detective: {result.TotalCollisions}");
+
+ UpdateProgress(70, "生成报告内容...");
+
+ // 生成报告内容
+ result.ReportContent = GenerateReportContent(collisionData, _parameters.Type, _parameters.IncludeDetails);
+
+ UpdateProgress(90, "处理报告显示...");
+
+ // 自动高亮(如果启用)
+ if (_parameters.AutoHighlight && collisionData.AllCollisions.Count > 0)
{
- UpdateProgress(30, "收集碰撞数据...");
-
- // 收集所有碰撞数据及统计信息
- var collisionData = CollectAllCollisionData();
- result.AllCollisions = collisionData.AllCollisions;
-
- // 修改统计数据
- var clashIntegration = ClashDetectiveIntegration.Instance;
- result.AnimationCollisions = clashIntegration?.AnimationCollisionCount ?? 0; // 检测点数量
- result.TotalCollisions = collisionData.ClashDetectiveCollisionCount;
- result.MovingObjectInfo = collisionData.MovingObjectInfo;
-
- // 新增:被撞物体清单
- result.CollidedObjectsList = collisionData.UniqueCollidedObjects.OrderBy(x => x).ToList();
- result.UniqueCollidedObjectsCount = collisionData.UniqueCollidedObjects.Count;
-
- LogManager.Info($"碰撞报告计数 - 检查点: {result.AnimationCollisions}, Clash Detective: {result.TotalCollisions}");
-
- UpdateProgress(70, "生成报告内容...");
-
- // 生成报告内容
- result.ReportContent = GenerateReportContent(collisionData, _parameters.Type, _parameters.IncludeDetails);
-
- UpdateProgress(90, "处理报告显示...");
-
- // 自动高亮(如果启用)
- if (_parameters.AutoHighlight && collisionData.AllCollisions.Count > 0)
+ try
{
- try
+ var highlightIntegration = ClashDetectiveIntegration.Instance;
+ if (highlightIntegration != null)
{
- var highlightIntegration = ClashDetectiveIntegration.Instance;
- if (highlightIntegration != null)
- {
- var highlightColor = Color.Green; // 绿色 (Navisworks API中没有Orange)
- highlightIntegration.ManageHighlightsByCategory("report", collisionData.AllCollisions, highlightColor, true);
- LogManager.Info($"自动高亮显示报告中的 {collisionData.AllCollisions.Count} 个碰撞对象");
- }
- }
- catch (Exception ex)
- {
- LogManager.Error($"自动高亮报告对象失败: {ex.Message}");
+ var highlightColor = Color.Green; // 绿色 (Navisworks API中没有Orange)
+ highlightIntegration.ManageHighlightsByCategory("report", collisionData.AllCollisions, highlightColor, true);
+ LogManager.Info($"自动高亮显示报告中的 {collisionData.AllCollisions.Count} 个碰撞对象");
}
}
+ catch (Exception ex)
+ {
+ LogManager.Error($"自动高亮报告对象失败: {ex.Message}");
+ }
+ }
- UpdateProgress(100, "报告生成完成");
+ UpdateProgress(100, "报告生成完成");
- }, cancellationToken);
-
- // 显示报告(必须在UI线程中执行)
+ // 显示报告(UI线程)
ShowReport(result);
+
+ // 将报告结果缓存起来
+ if (!string.IsNullOrEmpty(testNameKey))
+ {
+ lock (_cacheLock)
+ {
+ _reportCache[testNameKey] = result;
+ LogManager.Info($"碰撞报告已缓存: {testNameKey}, 缓存总数: {_reportCache.Count}");
+ }
+ }
}
catch (OperationCanceledException)
{
@@ -186,6 +239,64 @@ namespace NavisworksTransport.Commands
return PathPlanningResult.Success(result, message);
}
+ #region 缓存相关方法
+
+ ///
+ /// 获取当前最新的物流碰撞检测测试名称作为缓存键
+ ///
+ /// 测试名称,如果未找到则返回 null
+ private string GetLatestTestNameForCache()
+ {
+ try
+ {
+ var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
+ var documentClash = doc.GetClash();
+
+ if (documentClash == null)
+ {
+ LogManager.Warning("无法获取 Clash Detective 文档,无法生成缓存键");
+ return null;
+ }
+
+ // 查找最新的物流碰撞检测测试
+ var latestTest = documentClash.TestsData.Tests.Cast()
+ .Where(t => t.DisplayName.StartsWith("物流碰撞检测_"))
+ .OrderByDescending(t => t.DisplayName)
+ .FirstOrDefault();
+
+ if (latestTest != null)
+ {
+ LogManager.Debug($"缓存键用测试名称: {latestTest.DisplayName}");
+ return latestTest.DisplayName;
+ }
+ else
+ {
+ LogManager.Info("未找到物流碰撞检测测试,无法生成缓存键");
+ return null;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"获取测试名称作为缓存键失败: {ex.Message}");
+ return null;
+ }
+ }
+
+ ///
+ /// 清理过期缓存(可选功能)
+ ///
+ public static void ClearReportCache()
+ {
+ lock (_cacheLock)
+ {
+ var count = _reportCache.Count;
+ _reportCache.Clear();
+ LogManager.Info($"已清理碰撞报告缓存,共清理 {count} 个缓存项");
+ }
+ }
+
+ #endregion
+
///
/// 收集所有碰撞数据及统计信息
///
diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
index b08ef71..7f75ffb 100644
--- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
+++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs
@@ -8,6 +8,7 @@ using System.Windows.Threading;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Clash;
using NavisworksTransport.Core;
+using NavisworksTransport.Commands;
using NavisworksTransport.UI.WPF.Collections;
namespace NavisworksTransport.UI.WPF.ViewModels
@@ -541,7 +542,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
StartAnimationCommand = new RelayCommand(async () => await ExecuteStartAnimationAsync(), () => CanStartAnimation);
PauseAnimationCommand = new RelayCommand(async () => await ExecutePauseAnimationAsync(), () => CanPauseAnimation);
StopAnimationCommand = new RelayCommand(async () => await ExecuteStopAnimationAsync(), () => CanStopAnimation);
- ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReportAsync(), () => HasCollisionResults);
+ ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReport(), () => HasCollisionResults);
SelectAnimatedObjectCommand = new RelayCommand(ExecuteSelectAnimatedObject);
ClearAnimatedObjectCommand = new RelayCommand(ExecuteClearAnimatedObject, () => HasSelectedAnimatedObject);
GenerateAnimationCommand = new RelayCommand(ExecuteGenerateAnimation, () => CanGenerateAnimation);
@@ -683,65 +684,37 @@ namespace NavisworksTransport.UI.WPF.ViewModels
///
/// 查看碰撞报告命令
///
- private async Task ExecuteViewCollisionReportAsync()
+ private async Task ExecuteViewCollisionReport()
{
if (!HasCollisionResults)
{
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- UpdateMainStatus("尚无碰撞检测结果可查看");
- });
+ UpdateMainStatus("尚无碰撞检测结果可查看");
return;
}
try
{
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- UpdateMainStatus("正在生成碰撞报告...", -1, true);
- });
-
+ UpdateMainStatus("正在生成碰撞报告...", -1, true);
LogManager.Info("开始生成碰撞检测详细报告");
- // 在后台线程生成报告
- var reportData = await Task.Run(() =>
- {
- try
- {
- return GenerateCollisionReport();
- }
- catch (Exception ex)
- {
- LogManager.Error($"生成碰撞报告失败: {ex.Message}");
- return null;
- }
- });
+ // 直接调用完整的ViewCollisionReportCommand生成详细报告(在主线程上执行COM操作)
+ var viewReportCommand = NavisworksTransport.Commands.ViewCollisionReportCommand.CreateComprehensive();
+ var result = await viewReportCommand.ExecuteAsync();
- if (reportData != null)
+ if (result.IsSuccess)
{
- // 显示报告 - 可以通过多种方式显示
- await ShowCollisionReport(reportData);
-
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- UpdateMainStatus("碰撞报告已生成");
- LogManager.Info("碰撞报告生成完成并已显示");
- });
+ UpdateMainStatus("碰撞报告已生成");
+ LogManager.Info("碰撞报告生成完成并已显示");
}
else
{
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- UpdateMainStatus("生成碰撞报告失败");
- });
+ UpdateMainStatus($"报告生成失败: {result.ErrorMessage}");
+ LogManager.Error($"碰撞报告生成失败: {result.ErrorMessage}");
}
}
catch (Exception ex)
{
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- UpdateMainStatus("查看碰撞报告出错");
- });
+ UpdateMainStatus("查看碰撞报告出错");
LogManager.Error($"查看碰撞报告异常: {ex.Message}", ex);
}
}
@@ -1040,23 +1013,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
///
/// 处理碰撞检测事件
///
- private async void OnCollisionDetected(object sender, CollisionDetectedEventArgs e)
+ private void OnCollisionDetected(object sender, CollisionDetectedEventArgs e)
{
- await _uiStateManager.ExecuteUIUpdateAsync(() =>
- {
- HasCollisionResults = e.Results.Count > 0;
- var summary = e.Results.Count > 0
- ? $"发现 {e.Results.Count} 个碰撞点"
- : "未发现碰撞";
- UpdateMainStatus(summary);
- });
-
- // 自动生成并显示碰撞报告
- if (HasCollisionResults)
- {
- LogManager.Info("碰撞检测完成,自动生成报告");
- await ExecuteViewCollisionReportAsync();
- }
+ HasCollisionResults = e.Results.Count > 0;
+ var summary = e.Results.Count > 0
+ ? $"发现 {e.Results.Count} 个碰撞点"
+ : "未发现碰撞";
+ UpdateMainStatus(summary);
}
///
@@ -1658,31 +1621,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
});
- // 如果报告有效且有碰撞数据,显示详细报告窗口
+ // 如果报告有效且有碰撞数据,用户可通过"查看碰撞报告"按钮查看详细信息
if (reportData.IsValid && reportData.TotalCollisions > 0)
{
- // 调用ViewCollisionReportCommand显示详细报告窗口
- try
- {
- // 创建综合碰撞报告命令(现在不需要传递参数了!)
- var reportCommand = NavisworksTransport.Commands.ViewCollisionReportCommand.CreateComprehensive(autoHighlight: false);
-
- // 执行命令,UI显示会在正确的线程中处理
- var result = await reportCommand.ExecuteAsync();
-
- if (result.IsSuccess)
- {
- LogManager.Info("碰撞报告窗口已成功显示");
- }
- else
- {
- LogManager.Warning($"显示碰撞报告窗口失败: {result.ErrorMessage}");
- }
- }
- catch (Exception ex)
- {
- LogManager.Error($"调用碰撞报告命令失败: {ex.Message}");
- }
+ LogManager.Info($"碰撞检测完成,发现 {reportData.TotalCollisions} 个碰撞问题。用户可通过报告按钮查看详细信息");
}
else if (reportData.IsValid && reportData.TotalCollisions == 0)
{
diff --git a/src/UI/WPF/Views/CollisionReportDialog.xaml.cs b/src/UI/WPF/Views/CollisionReportDialog.xaml.cs
index cc9b0b5..5e04110 100644
--- a/src/UI/WPF/Views/CollisionReportDialog.xaml.cs
+++ b/src/UI/WPF/Views/CollisionReportDialog.xaml.cs
@@ -18,6 +18,16 @@ namespace NavisworksTransport.UI.WPF.Views
///
private CollisionReportViewModel _viewModel;
+ ///
+ /// 当前显示的碰撞报告窗口实例(单例模式)
+ ///
+ private static CollisionReportDialog _currentInstance = null;
+
+ ///
+ /// 用于线程同步的锁对象
+ ///
+ private static readonly object _lock = new object();
+
#endregion
#region 构造函数
@@ -106,6 +116,16 @@ namespace NavisworksTransport.UI.WPF.Views
_viewModel = null;
}
+ // 清除静态实例引用
+ lock (_lock)
+ {
+ if (_currentInstance == this)
+ {
+ _currentInstance = null;
+ LogManager.Info("碰撞报告对话框实例已从单例缓存中移除");
+ }
+ }
+
LogManager.Debug("碰撞报告对话框资源已清理");
}
catch (Exception ex)
@@ -198,18 +218,44 @@ namespace NavisworksTransport.UI.WPF.Views
catch (Exception ex)
{
LogManager.Error($"显示碰撞报告对话框失败: {ex.Message}");
- MessageBox.Show($"显示报告对话框失败: {ex.Message}", "错误",
+ MessageBox.Show($"显示报告对话框失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
return false;
}
}
+ ///
+ /// 激活并显示已存在的窗口
+ ///
+ private void ActivateWindow()
+ {
+ try
+ {
+ // 如果窗口被最小化,则恢复
+ if (this.WindowState == WindowState.Minimized)
+ {
+ this.WindowState = WindowState.Normal;
+ }
+
+ // 激活并前置窗口
+ this.Activate();
+ this.Topmost = true; // 暂时置顶
+ this.Topmost = false; // 然后取消置顶,但保持前置
+
+ LogManager.Info("碰撞报告对话框已激活并前置显示");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"激活碰撞报告对话框失败: {ex.Message}");
+ }
+ }
+
#endregion
#region 静态工厂方法
///
- /// 创建并显示碰撞报告对话框
+ /// 创建并显示碰撞报告对话框(单例模式)
///
/// 报告数据
/// 父窗口
@@ -218,23 +264,64 @@ namespace NavisworksTransport.UI.WPF.Views
{
try
{
- var dialog = new CollisionReportDialog(reportResult);
-
- if (owner != null)
+ lock (_lock)
{
- dialog.Owner = owner;
- }
+ // 如果当前已有实例且仍然打开,则更新数据并激活窗口
+ if (_currentInstance != null)
+ {
+ try
+ {
+ // 检查窗口是否仍然有效
+ if (_currentInstance.IsLoaded && _currentInstance.IsVisible)
+ {
+ LogManager.Info("检测到已存在的碰撞报告窗口,更新数据并激活窗口");
- // 异步显示对话框,避免阻塞UI
- dialog.Show();
-
- LogManager.Info("碰撞报告对话框已显示");
- return dialog;
+ // 更新数据
+ if (reportResult != null)
+ {
+ _currentInstance.UpdateReport(reportResult);
+ }
+
+ // 激活窗口
+ _currentInstance.ActivateWindow();
+
+ return _currentInstance;
+ }
+ else
+ {
+ // 窗口已关闭,清除引用
+ _currentInstance = null;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogManager.Warning($"检查现有窗口状态时出现异常: {ex.Message},将创建新窗口");
+ _currentInstance = null;
+ }
+ }
+
+ // 创建新的对话框实例
+ var dialog = new CollisionReportDialog(reportResult);
+
+ if (owner != null)
+ {
+ dialog.Owner = owner;
+ }
+
+ // 设置为当前实例
+ _currentInstance = dialog;
+
+ // 异步显示对话框,避免阻塞UI
+ dialog.Show();
+
+ LogManager.Info("新的碰撞报告对话框已显示");
+ return dialog;
+ }
}
catch (Exception ex)
{
LogManager.Error($"显示碰撞报告对话框失败: {ex.Message}");
- MessageBox.Show($"显示报告对话框失败: {ex.Message}", "错误",
+ MessageBox.Show($"显示报告对话框失败: {ex.Message}", "错误",
MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}