using Autodesk.Navisworks.Api.Plugins; using System; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.Integration; using NavisworksTransport.Core; using NavisworksTransport.Core.Animation; using NavisworksTransport.Core.Config; using NavisworksTransport.Utils; using NavisworksTransport.Utils.CoordinateSystem; using NavisApplication = Autodesk.Navisworks.Api.Application; namespace NavisworksTransport { /// /// 物流属性变更事件参数 /// public class LogisticsAttributeChangedEventArgs : EventArgs { public string OperationType { get; set; } // "修改" 或 "删除" public int AffectedCount { get; set; } // 受影响的模型数量 public string Message { get; set; } // 操作描述信息 public LogisticsAttributeChangedEventArgs(string operationType, int affectedCount, string message = "") { OperationType = operationType; AffectedCount = affectedCount; Message = message; } } /// /// 全局异常处理工具类 /// public static class GlobalExceptionHandler { private static bool _isInitialized = false; /// /// 初始化全局异常处理器 /// public static void Initialize() { if (_isInitialized) return; try { // 捕获未处理的异常 AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; // 捕获任务调度器未观察到的异常 System.Threading.Tasks.TaskScheduler.UnobservedTaskException += OnUnobservedTaskException; // 直接注册WinForms线程异常处理器(不调用SetUnhandledExceptionMode,避免插件环境下的警告) System.Windows.Forms.Application.ThreadException += OnThreadException; _isInitialized = true; LogManager.Info("[全局异常] 全局异常处理器已初始化"); } catch (Exception ex) { LogManager.Error($"[全局异常] 初始化异常处理器失败: {ex.Message}"); } } /// /// 处理未捕获的异常 /// private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) { try { Exception ex = e.ExceptionObject as Exception; string message = ex?.Message ?? "未知异常"; string stackTrace = ex?.StackTrace ?? "无堆栈信息"; LogManager.Error($"[全局异常] ===== 未处理异常发生 ====="); LogManager.Error($"[全局异常] 异常类型: {ex?.GetType().FullName ?? "Unknown"}"); LogManager.Error($"[全局异常] 异常消息: {message}"); LogManager.Error($"[全局异常] 是否终止进程: {e.IsTerminating}"); LogManager.Error($"[全局异常] 当前线程ID: {System.Threading.Thread.CurrentThread.ManagedThreadId}"); LogManager.Error($"[全局异常] 当前线程名称: {System.Threading.Thread.CurrentThread.Name ?? "未命名"}"); // 检查是否为特定类型的异常 if (ex is OutOfMemoryException) { LogManager.Error($"[全局异常] ⚠️ 内存不足异常"); var memoryUsage = GC.GetTotalMemory(false); LogManager.Error($"[全局异常] 当前内存使用: {memoryUsage / 1024 / 1024:F1} MB"); } else if (ex is StackOverflowException) { LogManager.Error($"[全局异常] ⚠️ 堆栈溢出异常"); } else if (ex is AccessViolationException) { LogManager.Error($"[全局异常] ⚠️ 访问违规异常"); } else if (ex is System.Runtime.InteropServices.SEHException) { LogManager.Error($"[全局异常] ⚠️ 结构化异常处理异常"); } LogManager.Error($"[全局异常] 堆栈跟踪:"); LogManager.Error(stackTrace); if (ex?.InnerException != null) { LogManager.Error($"[全局异常] 内部异常: {ex.InnerException.GetType().Name}: {ex.InnerException.Message}"); LogManager.Error($"[全局异常] 内部异常堆栈: {ex.InnerException.StackTrace}"); } // 显示用户友好的错误信息 ShowErrorDialog("程序发生未预期的错误", message, ex); // 尝试恢复关键组件 TryRecoverComponents(); LogManager.Error($"[全局异常] ===== 异常处理完成 ====="); } catch { // 异常处理中的异常,保持静默 } } /// /// 处理未观察到的任务异常 /// private static void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { try { Exception ex = e.Exception; LogManager.Error($"[全局异常] 未观察任务异常: {ex.Message}"); LogManager.Error($"[全局异常] 堆栈信息: {ex.StackTrace}"); LogManager.Error($"[全局异常] 异常类型: {ex.GetType().Name}"); // 标记异常已被观察,防止应用程序终止 e.SetObserved(); // 显示用户友好的错误信息 ShowErrorDialog("程序发生后台任务错误", ex.Message, ex); // 尝试恢复关键组件 TryRecoverComponents(); } catch { // 异常处理中的异常,保持静默 } } /// /// 处理线程异常 /// private static void OnThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { try { Exception ex = e.Exception; LogManager.Error($"[全局异常] 线程异常: {ex.Message}"); LogManager.Error($"[全局异常] 堆栈信息: {ex.StackTrace}"); LogManager.Error($"[全局异常] 异常类型: {ex.GetType().Name}"); // 显示用户友好的错误信息 ShowErrorDialog("程序发生线程错误", ex.Message, ex); // 尝试恢复关键组件 TryRecoverComponents(); } catch { // 异常处理中的异常,保持静默 } } /// /// 安全执行方法,捕获所有异常 /// public static T SafeExecute(Func action, T defaultValue = default, string operationName = "操作") { try { return action(); } catch (Exception ex) { LogManager.Error($"[安全执行] {operationName}失败: {ex.Message}"); LogManager.Error($"[安全执行] 堆栈信息: {ex.StackTrace}"); LogManager.Error($"[安全执行] 异常类型: {ex.GetType().Name}"); // 对于用户操作,显示简短的错误提示 if (!string.IsNullOrEmpty(operationName) && operationName != "操作") { ShowErrorToast($"{operationName}失败: {ex.Message}"); } return defaultValue; } } /// /// 安全执行方法(无返回值) /// public static void SafeExecute(Action action, string operationName = "操作") { SafeExecute(() => { action(); return true; }, false, operationName); } /// /// 显示错误对话框 /// private static void ShowErrorDialog(string title, string message, Exception ex = null) { try { string detailMessage = message; if (ex != null) { detailMessage += $"\n\n技术详情: {ex.GetType().Name}"; if (!string.IsNullOrEmpty(ex.Message)) { detailMessage += $"\n错误信息: {ex.Message}"; } } MessageBox.Show(detailMessage, title, MessageBoxButtons.OK, MessageBoxIcon.Error); } catch { // 如果连错误对话框都显示不了,就保持静默 } } /// /// 显示简短的错误提示 /// private static void ShowErrorToast(string message) { try { MessageBox.Show(message, "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); } catch { // 保持静默 } } /// /// 清理 Clash Detective 集成相关资源 /// public static void CleanupClashDetectiveIntegration() { try { LogManager.Info("[清理] 开始清理 Clash Detective 集成..."); // 清理 Clash Detective 集成 ClashDetectiveIntegration.Instance.Cleanup(); LogManager.Info("[清理] Clash Detective 集成清理完成"); } catch (Exception ex) { LogManager.Error($"[清理] Clash Detective 集成清理失败: {ex.Message}"); } } /// /// 尝试恢复关键组件 /// private static void TryRecoverComponents() { try { LogManager.Info("[全局异常] 尝试恢复关键组件..."); // 尝试重置路径编辑状态 var activeManager = PathPlanningManager.GetActivePathManager(); if (activeManager != null) { activeManager.ResetPathEditState(); LogManager.Info("[全局异常] 已重置路径编辑状态"); } // 尝试清除临时高亮 if (NavisApplication.ActiveDocument?.Models != null) { ModelHighlightHelper.ClearAllHighlights(); LogManager.Info("[全局异常] 已清除临时材质"); } // 清理 Clash Detective 集成 CleanupClashDetectiveIntegration(); LogManager.Info("[全局异常] 组件恢复完成"); } catch (Exception ex) { LogManager.Error($"[全局异常] 组件恢复失败: {ex.Message}"); } } } [Plugin("NavisworksTransport.Main", "Tian", DisplayName = "物流路径规划", ToolTip = "物流路径规划和动画仿真插件")] [DockPanePlugin(420, 700, FixedSize = false, AutoScroll = true)] public class Main : DockPanePlugin { /// /// 构造函数,提前初始化全局异常处理器 /// // 状态跟踪变量(用于观察Models.CollectionChanged事件) private bool _hasModels = false; private int _eventCount = 0; private DateTime _pluginStartTime = DateTime.Now; public Main() { // 在任何控件创建之前初始化全局异常处理器 GlobalExceptionHandler.Initialize(); } /// /// 插件加载后调用(Navisworks插件生命周期) /// protected override void OnLoaded() { base.OnLoaded(); _pluginStartTime = DateTime.Now; // 记录插件启动时间 LogManager.Info("[文档管理] 插件OnLoaded - 开始初始化"); //显式初始化配置管理器,确保配置加载完成 try { var config = ConfigManager.Instance.Current; LogManager.Info($"[配置管理] 配置已加载"); // 检查配置兼容性 if (ConfigManager.Instance.HasMissingConfigItems) { var message = ConfigManager.Instance.GetConfigCompatibilityMessage(); LogManager.Warning($"[配置管理] {message}"); // 延迟显示配置兼容性提示(避免在插件加载时阻塞) Task.Delay(3000).ContinueWith(_ => { try { // 使用 Navisworks 的 API 显示消息框 System.Windows.Application.Current.Dispatcher.Invoke(() => { System.Windows.MessageBox.Show( message, "配置文件需要升级", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning); }); } catch (Exception msgEx) { LogManager.Error($"[配置管理] 显示兼容性提示失败: {msgEx.Message}"); } }); } // 注意:坐标系初始化推迟到 InitializeManagers() 中进行 // 因为此时文档可能尚未加载,无法正确检测坐标系 } catch (Exception ex) { LogManager.Error($"[配置管理] 配置加载失败: {ex.Message}"); } // 订阅文档事件 SubscribeToDocumentEvents(); // 检查是否已有活动文档且包含模型 var activeDoc = NavisApplication.ActiveDocument; if (activeDoc != null && activeDoc.Models != null && activeDoc.Models.Count > 0) { LogManager.Info("[文档管理] 插件加载时发现包含模型的活动文档,立即初始化管理器"); InitializeManagers(); } else if (activeDoc != null) { LogManager.Info("[文档管理] 插件加载时发现空文档(无模型),等待文档加载完成"); } else { LogManager.Info("[文档管理] 插件加载时无活动文档"); } } /// /// 插件卸载前调用(Navisworks插件生命周期) /// protected override void OnUnloading() { LogManager.Info("[文档管理] 插件OnUnloading - 开始清理"); // 取消订阅文档事件 UnsubscribeFromDocumentEvents(); // 清理管理器 CleanupManagers(); base.OnUnloading(); } /// /// 订阅文档相关事件 /// private void SubscribeToDocumentEvents() { try { // 订阅文档切换前事件(保留用于未来兼容性) NavisApplication.ActiveDocumentChanging += OnActiveDocumentChanging; // 订阅文档切换后事件(保留用于未来兼容性) NavisApplication.ActiveDocumentChanged += OnActiveDocumentChanged; // 订阅模型集合变化事件(SDI架构下的真正文档变化事件) if (NavisApplication.ActiveDocument != null) { NavisApplication.ActiveDocument.Models.CollectionChanged += OnModelsCollectionChanged; LogManager.Info("[文档管理] 已订阅模型集合变化事件"); } LogManager.Info("[文档管理] 已订阅文档相关事件(Changing + Changed + Models.CollectionChanged)"); } catch (Exception ex) { LogManager.Error($"[文档管理] 订阅文档事件失败: {ex.Message}"); } } /// /// 活动文档切换前事件处理 /// private void OnActiveDocumentChanging(object sender, EventArgs e) { LogManager.Info($"[文档管理] 文档即将切换,当前文档: {NavisApplication.ActiveDocument?.FileName ?? "无"}"); // 取消订阅旧文档的Models.CollectionChanged事件 if (NavisApplication.ActiveDocument != null) { try { NavisApplication.ActiveDocument.Models.CollectionChanged -= OnModelsCollectionChanged; LogManager.Info("[文档管理] 已取消订阅旧文档的模型集合变化事件"); } catch (Exception ex) { LogManager.Warning($"[文档管理] 取消订阅旧文档事件时出现警告: {ex.Message}"); } } // 清理旧文档的状态 CleanupManagers(); } /// /// 活动文档切换事件处理 /// private void OnActiveDocumentChanged(object sender, EventArgs e) { LogManager.Info($"[文档管理] 文档已切换到: {NavisApplication.ActiveDocument?.FileName ?? "无活动文档"}"); // 清除单位转换缓存(文档切换后单位可能不同) Utils.UnitsConverter.ClearCache(); GlobalExceptionHandler.SafeExecute(() => { var activeDoc = NavisApplication.ActiveDocument; // 如果有新的活动文档,订阅其Models.CollectionChanged事件 if (activeDoc != null) { try { activeDoc.Models.CollectionChanged += OnModelsCollectionChanged; LogManager.Info("[文档管理] 已订阅新文档的模型集合变化事件"); } catch (Exception ex) { LogManager.Warning($"[文档管理] 订阅新文档事件时出现警告: {ex.Message}"); } InitializeManagers(); } else { LogManager.Info("[文档管理] 当前无活动文档"); } }, "处理活动文档切换事件"); } /// /// 模型集合变化事件处理 /// private void OnModelsCollectionChanged(object sender, EventArgs e) { _eventCount++; var activeDoc = NavisApplication.ActiveDocument; var modelCount = activeDoc?.Models?.Count ?? 0; bool currentHasModels = modelCount > 0; var timeSinceStart = (DateTime.Now - _pluginStartTime).TotalSeconds; LogManager.Info("========================================"); LogManager.Info($"[文档管理] Models.CollectionChanged 事件 #{_eventCount}"); LogManager.Info($"[文档管理] 触发时间: 插件启动后 {timeSinceStart:F1} 秒"); LogManager.Info($"[文档管理] 当前Models.Count = {modelCount}"); LogManager.Info($"[文档管理] 状态变化: {(_hasModels ? "有模型" : "无模型")} -> {(currentHasModels ? "有模型" : "无模型")}"); LogManager.Info($"[文档管理] 文档文件名: {activeDoc?.FileName ?? "空"}"); LogManager.Info($"[文档管理] 文档标题: {activeDoc?.Title ?? "空"}"); // 分析状态变化类型并执行相应操作 if (!_hasModels && currentHasModels) { LogManager.Info($"[文档管理] *** 状态分析: 从无到有(可能是打开文档)***"); // 文档加载完成,初始化PathDatabase if (!string.IsNullOrEmpty(activeDoc?.FileName)) { try { var pathManager = PathPlanningManager.GetActivePathManager(); if (pathManager != null) { pathManager.DatabaseInitialize(); } } catch (Exception ex) { // 数据库初始化失败是严重错误,需要明确提示用户 var errorMsg = $"数据库初始化失败:{ex.Message}\n\n"; errorMsg += "可能的原因:\n"; errorMsg += "1. 文件夹权限不足\n"; errorMsg += "2. 磁盘空间不足\n"; errorMsg += "3. 数据库文件被锁定\n"; errorMsg += "4. SQLite 组件损坏\n\n"; errorMsg += "详细信息请查看日志文件。"; LogManager.Error($"[文档管理] 数据库初始化失败: {ex.Message}", ex); LogManager.Error($"[文档管理] 文档路径: {activeDoc.FileName}"); LogManager.Error($"[文档管理] 异常类型: {ex.GetType().Name}"); LogManager.Error($"[文档管理] 堆栈信息: {ex.StackTrace}"); System.Windows.MessageBox.Show( errorMsg, "数据库初始化失败", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error ); // 不重新抛出,避免插件崩溃,但批处理等功能将不可用 } } } else if (_hasModels && !currentHasModels) { LogManager.Info($"[文档管理] *** 状态分析: 从有到无(可能是关闭文档)***"); } else if (!_hasModels && !currentHasModels) { LogManager.Info($"[文档管理] *** 状态分析: 保持无模型状态 ***"); } else if (_hasModels && currentHasModels) { LogManager.Info($"[文档管理] *** 状态分析: 保持有模型状态(模型数量变化)***"); } LogManager.Info("========================================"); // 更新状态 _hasModels = currentHasModels; } /// /// 为当前文档初始化坐标系 /// 在文档加载完成后调用,确保可以正确检测 Document.UpVector /// private void InitializeCoordinateSystemForDocument() { try { var config = ConfigManager.Instance.Current; if (config?.CoordinateSystem == null) { LogManager.Warning("[坐标系] 配置中缺少坐标系设置,使用默认自动检测"); CoordinateSystemManager.Instance.Initialize(CoordinateSystemType.AutoDetect); return; } // 如果已经初始化且不是 AutoDetect 模式,则跳过 // 这样用户手动设置的坐标系不会在文档切换时被覆盖 if (CoordinateSystemManager.Instance.Current != null && CoordinateSystemManager.Instance.ConfiguredType != CoordinateSystemType.AutoDetect) { LogManager.Debug("[坐标系] 使用手动指定的坐标系,跳过自动检测"); return; } // 解析坐标系类型配置 CoordinateSystemType coordType; var typeString = config.CoordinateSystem.Type?.Trim() ?? "AutoDetect"; switch (typeString.ToLowerInvariant()) { case "zup": case "z-up": coordType = CoordinateSystemType.ZUp; break; case "yup": case "y-up": coordType = CoordinateSystemType.YUp; break; case "autodetect": case "auto": default: coordType = CoordinateSystemType.AutoDetect; break; } // 初始化坐标系 CoordinateSystemManager.Instance.Initialize(coordType); var currentCS = CoordinateSystemManager.Instance.Current; LogManager.Info($"[坐标系] 初始化完成 - {currentCS}"); } catch (Exception ex) { LogManager.Error($"[坐标系] 初始化失败: {ex.Message},使用默认 Z-Up"); CoordinateSystemManager.Instance.Initialize(CoordinateSystemType.ZUp); } } /// /// 初始化各个管理器 /// private void InitializeManagers() { try { var activeDoc = NavisApplication.ActiveDocument; if (activeDoc == null) { LogManager.Warning("[文档管理] 无活动文档,跳过初始化"); return; } LogManager.Info($"[文档管理] 开始为文档 '{activeDoc.FileName ?? "未保存"}' 初始化管理器..."); // 初始化坐标系(文档已加载,可以正确检测) InitializeCoordinateSystemForDocument(); // 通知DocumentStateManager文档已就绪 DocumentStateManager.Instance.OnDocumentReady(); // 清理并重新初始化各种缓存 ClashDetectiveIntegration.ClearAllCaches(); LogManager.Info("[文档管理] 管理器初始化完成"); } catch (Exception ex) { LogManager.Error($"[文档管理] 初始化管理器失败: {ex.Message}"); } } /// /// 清理所有管理器状态 /// private void CleanupManagers() { try { LogManager.Info("[文档管理] 开始清理管理器..."); // 通知DocumentStateManager文档已失效 DocumentStateManager.Instance.OnDocumentInvalidated(); // 停止所有动画(程序关闭专用) try { var animationManager = PathAnimationManager.GetInstance(); if (animationManager != null) { animationManager.ShutdownAnimation(); // 使用关闭专用方法,不执行UI操作 animationManager.ClearReferences(); } } catch (Exception ex) { LogManager.Warning($"[文档管理] 清理动画管理器时出现警告: {ex.Message}"); } // 清理路径规划管理器 try { var pathManager = PathPlanningManager.GetActivePathManager(); if (pathManager != null) { pathManager.ResetPathEditState(); pathManager.ClearInvalidReferences(); } } catch (Exception ex) { LogManager.Warning($"[文档管理] 清理路径管理器时出现警告: {ex.Message}"); } // 清理路径渲染插件的可视化 try { var renderPlugin = PathPointRenderPlugin.Instance; if (renderPlugin != null) { renderPlugin.ClearAllPaths(); LogManager.Info("[文档管理] 已清理路径可视化"); } } catch (Exception ex) { LogManager.Warning($"[文档管理] 清理路径可视化时出现警告: {ex.Message}"); } // 清理碰撞检测缓存 try { ClashDetectiveIntegration.Instance?.ClearCollisionCache(); } catch (Exception ex) { LogManager.Warning($"[文档管理] 清理碰撞检测缓存时出现警告: {ex.Message}"); } // 清理IdleEventManager任务 try { IdleEventManager.Instance?.Dispose(); } catch (Exception ex) { LogManager.Warning($"[文档管理] 清理Idle事件管理器时出现警告: {ex.Message}"); } // 清理虚拟车辆 try { VirtualVehicleManager.Instance.Cleanup(); LogManager.Info("[文档管理] 已清理虚拟车辆"); } catch (Exception ex) { LogManager.Warning($"[文档管理] 清理虚拟车辆时出现警告: {ex.Message}"); } // 清除临时材质 try { var activeDoc = NavisApplication.ActiveDocument; if (activeDoc?.Models != null) { ModelHighlightHelper.ClearAllHighlights(); } } catch (Exception ex) { LogManager.Warning($"[文档管理] 清除临时材质时出现警告: {ex.Message}"); } LogManager.Info("[文档管理] 管理器清理完成"); } catch (Exception ex) { LogManager.Error($"[文档管理] 清理管理器失败: {ex.Message}"); } } public override Control CreateControlPane() { try { LogManager.Info("=== 开始创建DockPane控制面板 ==="); // 使用官方示例的最简单实现 LogManager.Info("创建ElementHost..."); ElementHost eh = new ElementHost { AutoSize = true }; LogManager.Info("创建LogisticsControlPanel..."); eh.Child = new UI.WPF.LogisticsControlPanel(); LogManager.Info("调用CreateControl()..."); eh.CreateControl(); LogManager.Info("=== DockPane控制面板创建成功 ==="); return eh; } catch (Exception ex) { LogManager.Error($"=== CreateControlPane失败: {ex.Message} ==="); LogManager.Error($"异常类型: {ex.GetType().FullName}"); LogManager.Error($"堆栈跟踪: {ex.StackTrace}"); // 返回null会导致Navisworks立即调用DestroyControlPane throw; // 重新抛出异常让Navisworks知道创建失败 } } public override void DestroyControlPane(Control pane) { GlobalExceptionHandler.SafeExecute(() => { LogManager.Info("开始销毁DockPane控制面板"); // 清理WPF控件资源 if (pane is ElementHost elementHost && elementHost.Child is UI.WPF.LogisticsControlPanel wpfControl) { // 清理WPF控件资源 wpfControl.Cleanup(); elementHost.Child = null; } // 取消订阅文档事件 UnsubscribeFromDocumentEvents(); // 释放控件资源 pane?.Dispose(); LogManager.Info("DockPane控制面板销毁完成"); }, "销毁控制面板"); } /// /// 取消订阅文档相关事件 /// private void UnsubscribeFromDocumentEvents() { try { // 取消订阅文档切换事件 NavisApplication.ActiveDocumentChanging -= OnActiveDocumentChanging; NavisApplication.ActiveDocumentChanged -= OnActiveDocumentChanged; // 取消订阅当前文档的Models.CollectionChanged事件 if (NavisApplication.ActiveDocument != null) { try { NavisApplication.ActiveDocument.Models.CollectionChanged -= OnModelsCollectionChanged; LogManager.Info("[文档管理] 已取消订阅模型集合变化事件"); } catch (Exception ex) { LogManager.Warning($"[文档管理] 取消订阅模型集合事件时出现警告: {ex.Message}"); } } LogManager.Info("[文档管理] 已取消订阅所有文档相关事件"); } catch (Exception ex) { LogManager.Error($"[文档管理] 取消订阅文档事件失败: {ex.Message}"); } } } }