From cddb7de71e73cbae3b87b2875989ed17a7a0c755 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Tue, 19 Aug 2025 00:26:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BA=86=E5=88=86=E5=B1=82?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E7=9A=84=E5=8A=9F=E8=83=BD=EF=BC=8C=E8=BF=98?= =?UTF-8?q?=E6=98=AF=E7=BA=BF=E7=A8=8B=E5=AE=89=E5=85=A8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../document_symbols_cache_v23-06-25.pkl | Bin 27955016 -> 27945069 bytes NavisworksTransportPlugin.csproj | 1 - src/Core/ModelSplitterManager.cs | 57 +- src/Core/SimplifiedModelSplitterManager.cs | 434 +++---- src/Utils/NavisworksFileExporter.cs | 1014 ----------------- 5 files changed, 224 insertions(+), 1282 deletions(-) delete mode 100644 src/Utils/NavisworksFileExporter.cs diff --git a/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl b/.serena/cache/csharp/document_symbols_cache_v23-06-25.pkl index 0b291187b55ce618db2a6903c281ae330428890a..e1f17f24972e1769aa3f0437b5d1eee02ade0de3 100644 GIT binary patch delta 89930 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 LRl!%@E~S3}D6i&< delta 91706 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

dkG5Y;5D7BGvXA&&31L~qV@ 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 R?(i?x{;hp0{gwWM#y=wKe - diff --git a/src/Core/ModelSplitterManager.cs b/src/Core/ModelSplitterManager.cs index b6e4897..0ca0d79 100644 --- a/src/Core/ModelSplitterManager.cs +++ b/src/Core/ModelSplitterManager.cs @@ -139,7 +139,6 @@ namespace NavisworksTransport private readonly FloorDetector _floorDetector; private readonly AttributeGrouper _attributeGrouper; - private readonly NavisworksFileExporter _fileExporter; private bool _isSplitting = false; #endregion @@ -150,7 +149,6 @@ namespace NavisworksTransport { _floorDetector = new FloorDetector(); _attributeGrouper = new AttributeGrouper(); - _fileExporter = new NavisworksFileExporter(); LogManager.Info("[ModelSplitter] 模型分层管理器已初始化"); } @@ -597,7 +595,60 @@ namespace NavisworksTransport LogManager.Info("[ModelSplitter] 开始导出文件..."); LogManager.Info($"[ModelSplitter] 目标文件: {result.OutputFilePath}"); - bool exportSuccess = await _fileExporter.ExportModelItemsAsync(preview.Items, result.OutputFilePath); + // 直接使用 Navisworks API 导出 + bool exportSuccess = false; + try + { + var document = NavisApplication.ActiveDocument; + + // 保存当前可见性状态并重置 + document.Models.ResetAllHidden(); + + // 隐藏不需要的项目 + var allItems = new ModelItemCollection(); + allItems.AddRange(document.Models.RootItemDescendantsAndSelf); + + var itemsToHide = new ModelItemCollection(); + foreach (ModelItem item in allItems) + { + bool shouldKeep = false; + foreach (ModelItem exportItem in preview.Items) + { + if (item.Equals(exportItem)) + { + shouldKeep = true; + break; + } + } + + if (!shouldKeep) + { + itemsToHide.Add(item); + } + } + + if (itemsToHide.Count > 0) + { + document.Models.SetHidden(itemsToHide, true); + } + + // 创建导出选项并导出 + var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions(); + exportOptions.ExcludeHiddenItems = true; + exportOptions.EmbedXrefs = false; + exportOptions.PreventObjectPropertyExport = false; + + document.ExportToNwd(result.OutputFilePath, exportOptions); + exportSuccess = true; + + // 恢复可见性 + document.Models.ResetAllHidden(); + } + catch (Exception ex) + { + LogManager.Error($"[ModelSplitter] 导出异常: {ex.Message}"); + exportSuccess = false; + } LogManager.Info($"[ModelSplitter] 文件导出结果: {exportSuccess}"); diff --git a/src/Core/SimplifiedModelSplitterManager.cs b/src/Core/SimplifiedModelSplitterManager.cs index 53b6748..ff791d4 100644 --- a/src/Core/SimplifiedModelSplitterManager.cs +++ b/src/Core/SimplifiedModelSplitterManager.cs @@ -110,7 +110,6 @@ namespace NavisworksTransport private readonly FloorDetector _floorDetector; private readonly AttributeGrouper _attributeGrouper; - private readonly NavisworksFileExporter _fileExporter; // 楼层检测结果缓存 private readonly Dictionary> _floorCache; @@ -125,7 +124,6 @@ namespace NavisworksTransport { _floorDetector = new FloorDetector(); _attributeGrouper = new AttributeGrouper(); - _fileExporter = new NavisworksFileExporter(); // 初始化缓存 _floorCache = new Dictionary>(); @@ -974,20 +972,158 @@ namespace NavisworksTransport var itemsToExport = preview.Items; LogManager.Info($"[SimplifiedModelSplitter] 将导出 {itemsToExport.Count} 个模型项"); - // 使用异步方法导出 - var exportTask = _fileExporter.ExportModelItemsAsync(itemsToExport, outputPath); - bool exportSuccess = exportTask.Result; + // 检查线程状态 + var apartmentState = System.Threading.Thread.CurrentThread.GetApartmentState(); + LogManager.Info($"[SimplifiedModelSplitter] 当前线程状态: {apartmentState}"); - if (exportSuccess) + // 核心修复:确保在主 UI 线程中执行 Navisworks API 调用 + bool exportResult = false; + Exception exportException = null; + + // 使用 Application.Current.Dispatcher.Invoke 确保在主线程中执行 + System.Windows.Application.Current.Dispatcher.Invoke(() => { - LogManager.Info($"[SimplifiedModelSplitter] ========== ExportLayerToNwd完成 ========== 成功导出到: {outputPath}"); - return true; - } - else + try + { + LogManager.Info($"[SimplifiedModelSplitter] 在主线程中执行导出操作"); + var document = NavisApplication.ActiveDocument; + + // 保存当前可见性状态(在主线程中) + LogManager.Info($"[SimplifiedModelSplitter] 开始保存当前可见性状态"); + var originalVisibilityState = SaveCurrentVisibilityState(document); + LogManager.Info($"[SimplifiedModelSplitter] 已保存 {originalVisibilityState.Count} 个项目的可见性状态"); + + try + { + // 采用智能隐藏策略:只操作顶级节点,避免遍历所有项目 + var allTopLevelItems = new List(); + + // 只获取顶级节点,不遍历全部项目 + foreach (Model model in document.Models) + { + foreach (ModelItem topLevelItem in model.RootItem.Children) + { + allTopLevelItems.Add(topLevelItem); + } + } + + LogManager.Info($"[SimplifiedModelSplitter] 收集到 {allTopLevelItems.Count} 个顶级节点"); + + // 智能隐藏策略:如果顶级节点包含要导出的项目,则保持可见;否则隐藏整个顶级分支 + var itemsToHide = new ModelItemCollection(); + int hiddenCount = 0; + + foreach (ModelItem topLevelItem in allTopLevelItems) + { + bool shouldKeepTopLevel = false; + + // 检查这个顶级节点本身是否在导出列表中 + foreach (ModelItem exportItem in itemsToExport) + { + if (topLevelItem.Equals(exportItem)) + { + shouldKeepTopLevel = true; + LogManager.Info($"[SimplifiedModelSplitter] 顶级节点 {topLevelItem.DisplayName} 本身被选中,保持可见"); + break; + } + } + + // 如果顶级节点本身不在导出列表中,检查是否有任何导出项是它的后代 + if (!shouldKeepTopLevel) + { + foreach (var exportItem in itemsToExport) + { + var current = exportItem; + while (current != null) + { + if (current == topLevelItem) + { + shouldKeepTopLevel = true; + LogManager.Info($"[SimplifiedModelSplitter] 顶级节点 {topLevelItem.DisplayName} 包含导出项目,保持可见"); + break; + } + current = current.Parent; + } + if (shouldKeepTopLevel) break; + } + } + + // 如果这个顶级节点不需要保持可见,则隐藏它 + if (!shouldKeepTopLevel) + { + try + { + itemsToHide.Add(topLevelItem); + hiddenCount++; + LogManager.Info($"[SimplifiedModelSplitter] 隐藏顶级节点: {topLevelItem.DisplayName}"); + } + catch (Exception ex) + { + LogManager.Warning($"[SimplifiedModelSplitter] 添加隐藏项目失败: {topLevelItem.DisplayName} - {ex.Message}"); + } + } + } + + // 执行隐藏操作 + if (itemsToHide.Count > 0) + { + try + { + document.Models.SetHidden(itemsToHide, true); + LogManager.Info($"[SimplifiedModelSplitter] 成功隐藏 {hiddenCount} 个顶级节点,保留导出项目可见"); + } + catch (Exception ex) + { + LogManager.Warning($"[SimplifiedModelSplitter] 隐藏操作失败: {ex.Message}"); + } + } + + // 创建导出选项 + var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions + { + ExcludeHiddenItems = true, // 只导出可见项目 + EmbedXrefs = false, + PreventObjectPropertyExport = false + }; + + LogManager.Info($"[SimplifiedModelSplitter] 开始调用ExportToNwd API(主线程)"); + + // 在主线程中执行导出 + document.ExportToNwd(outputPath, exportOptions); + + LogManager.Info($"[SimplifiedModelSplitter] ExportToNwd API调用完成(主线程)"); + exportResult = true; + } + finally + { + // 恢复原始可见性状态(在主线程中) + try + { + RestoreVisibilityState(document, originalVisibilityState); + LogManager.Info($"[SimplifiedModelSplitter] 已恢复原始可见性状态"); + } + catch (Exception restoreEx) + { + LogManager.Error($"[SimplifiedModelSplitter] 恢复可见性失败: {restoreEx.Message}"); + } + } + } + catch (Exception ex) + { + exportException = ex; + } + }); + + // 检查导出结果 + if (exportException != null) { - LogManager.Error($"[SimplifiedModelSplitter] 导出失败: {outputPath}"); + LogManager.Error($"[SimplifiedModelSplitter] 主线程导出异常: {exportException.Message}"); + LogManager.Error($"[SimplifiedModelSplitter] 异常堆栈: {exportException.StackTrace}"); return false; } + + LogManager.Info($"[SimplifiedModelSplitter] ========== ExportLayerToNwd完成 ========== 成功导出到: {outputPath}"); + return exportResult; } catch (Exception ex) { @@ -997,157 +1133,41 @@ namespace NavisworksTransport } } - ///

- /// 根据分层结果获取该层包含的模型项 + /// 保存当前可见性状态(参考"保存当前选择项"的方法) /// - private ModelItemCollection GetLayerModelItems(SplitPreviewResult preview, SplitConfiguration config) + private Dictionary SaveCurrentVisibilityState(Document document) { + var visibilityState = new Dictionary(); + try { - LogManager.Info($"[SimplifiedModelSplitter] ========== GetLayerModelItems开始 =========="); - LogManager.Info($"[SimplifiedModelSplitter] 目标分层: {preview.LayerName}, 策略: {config.Strategy}"); - - // 优先使用预览结果中已缓存的模型项 - if (preview.Items != null && preview.Items.Count > 0) + // 获取所有顶级项目并记录它们的可见性状态 + foreach (Model model in document.Models) { - LogManager.Info($"[SimplifiedModelSplitter] 使用预览结果中的缓存模型项,数量: {preview.Items.Count}"); - - // 关键修复:展开楼层顶层节点,收集所有子节点 - LogManager.Info($"[SimplifiedModelSplitter] 开始展开楼层节点,收集完整的子节点内容..."); - var expandedItems = ExpandFloorItems(preview.Items); - LogManager.Info($"[SimplifiedModelSplitter] 楼层节点展开完成: 原始{preview.Items.Count}个 -> 展开后{expandedItems.Count}个"); - - return expandedItems; + foreach (ModelItem topLevelItem in model.RootItem.Children) + { + try + { + // 记录是否隐藏(IsHidden为true表示隐藏,我们存储可见性所以取反) + visibilityState[topLevelItem] = !topLevelItem.IsHidden; + } + catch + { + // 如果无法获取状态,默认为可见 + visibilityState[topLevelItem] = true; + } + } } - LogManager.Info($"[SimplifiedModelSplitter] 预览结果中没有模型项,开始重新检测"); - - var document = NavisApplication.ActiveDocument; - if (document?.Models?.Count == 0) - { - LogManager.Warning($"[SimplifiedModelSplitter] 文档无效或没有模型"); - return new ModelItemCollection(); - } - - var allItems = GetAllModelItems(config.MaxDepth); - LogManager.Info($"[SimplifiedModelSplitter] 获取到总模型项数: {allItems.Count},深度: {config.MaxDepth}"); - var layerItems = new ModelItemCollection(); - - switch (config.Strategy) - { - case SplitStrategy.ByFloor: - LogManager.Info($"[SimplifiedModelSplitter] 使用楼层策略,开始重新检测楼层"); - // 按楼层分层:使用FloorDetector重新检测并匹配层名 - var floors = _floorDetector.DetectFloors(allItems, null, config.MaxDepth); - LogManager.Info($"[SimplifiedModelSplitter] 检测到楼层数: {floors?.Count ?? 0}"); - - if (floors != null) - { - foreach (var floor in floors) - { - string sanitizedFloorName = SanitizeLayerName(floor.FloorName); - LogManager.Info($"[SimplifiedModelSplitter] 楼层匹配检查: 原始名称='{floor.FloorName}' -> 清理后='{sanitizedFloorName}', 目标='{preview.LayerName}', 匹配={sanitizedFloorName == preview.LayerName}"); - } - } - - var matchingFloor = floors?.FirstOrDefault(f => SanitizeLayerName(f.FloorName) == preview.LayerName); - if (matchingFloor != null) - { - LogManager.Info($"[SimplifiedModelSplitter] 找到匹配楼层: 原始名称='{matchingFloor.FloorName}', 清理后名称='{preview.LayerName}', 包含模型项: {matchingFloor.ItemCount}"); - - // 关键修复:直接使用FloorDetector检测结果,并展开所有子节点 - if (matchingFloor.Items != null && matchingFloor.Items.Count > 0) - { - LogManager.Info($"[SimplifiedModelSplitter] 直接使用FloorDetector的模型项结果,数量: {matchingFloor.Items.Count}"); - LogManager.Info($"[SimplifiedModelSplitter] 开始展开楼层节点,收集完整的子节点内容..."); - - // 展开楼层顶层节点,收集所有子节点 - var expandedItems = ExpandFloorItems(matchingFloor.Items); - LogManager.Info($"[SimplifiedModelSplitter] 楼层节点展开完成: 原始{matchingFloor.Items.Count}个 -> 展开后{expandedItems.Count}个"); - - layerItems = expandedItems; - } - else - { - LogManager.Info($"[SimplifiedModelSplitter] FloorDetector结果中没有模型项,使用原始名称重新查找: '{matchingFloor.FloorName}'"); - var foundItems = GetFloorItems(allItems, matchingFloor.FloorName, config.MaxDepth); - LogManager.Info($"[SimplifiedModelSplitter] 重新查找结果: {foundItems.Count}个模型项"); - - // 同样展开找到的楼层项目 - if (foundItems.Count > 0) - { - var expandedItems = ExpandFloorItems(foundItems); - LogManager.Info($"[SimplifiedModelSplitter] 重新查找的楼层项目展开完成: 原始{foundItems.Count}个 -> 展开后{expandedItems.Count}个"); - layerItems = expandedItems; - } - else - { - layerItems = foundItems; - } - } - } - else - { - LogManager.Warning($"[SimplifiedModelSplitter] 未找到匹配的楼层: {preview.LayerName}"); - } - break; - - case SplitStrategy.ByAttribute: - LogManager.Info($"[SimplifiedModelSplitter] 使用属性策略: {config.AttributeName}"); - // 按属性分层:使用AttributeGrouper重新分组并匹配层名 - var groups = _attributeGrouper.GroupByAttribute(allItems, config.AttributeName); - LogManager.Info($"[SimplifiedModelSplitter] 检测到属性组数: {groups?.Count ?? 0}"); - - if (groups != null) - { - foreach (var group in groups) - { - string sanitizedGroupName = SanitizeLayerName(group.GroupName); - LogManager.Info($"[SimplifiedModelSplitter] 属性组匹配检查: 原始名称='{group.GroupName}' -> 清理后='{sanitizedGroupName}', 目标='{preview.LayerName}', 匹配={sanitizedGroupName == preview.LayerName}"); - } - } - - var matchingGroup = groups?.FirstOrDefault(g => SanitizeLayerName(g.GroupName) == preview.LayerName); - if (matchingGroup != null) - { - LogManager.Info($"[SimplifiedModelSplitter] 找到匹配属性组: 原始名称='{matchingGroup.GroupName}', 清理后名称='{preview.LayerName}', 包含模型项: {matchingGroup.ItemCount}"); - - // 直接使用AttributeGrouper检测结果中的模型项,避免重新检测 - if (matchingGroup.Items != null && matchingGroup.Items.Count > 0) - { - LogManager.Info($"[SimplifiedModelSplitter] 直接使用AttributeGrouper的模型项结果,数量: {matchingGroup.Items.Count}"); - // 属性分组通常已经是完整的构件,不需要展开,但为了保持一致性,仍然检查 - var expandedItems = ExpandFloorItems(matchingGroup.Items); - LogManager.Info($"[SimplifiedModelSplitter] 属性组项目展开完成: 原始{matchingGroup.Items.Count}个 -> 展开后{expandedItems.Count}个"); - layerItems = expandedItems; - } - else - { - LogManager.Info($"[SimplifiedModelSplitter] AttributeGrouper结果中没有模型项,使用原始名称重新查找: '{matchingGroup.GroupName}'"); - layerItems = GetAttributeGroupItems(allItems, config.AttributeName, matchingGroup.GroupName); - } - } - else - { - LogManager.Warning($"[SimplifiedModelSplitter] 未找到匹配的属性组: {preview.LayerName}"); - } - break; - - default: - LogManager.Warning($"[SimplifiedModelSplitter] 不支持的分层策略: {config.Strategy}"); - break; - } - - LogManager.Info($"[SimplifiedModelSplitter] ========== GetLayerModelItems完成 ========== 获取到 {layerItems.Count} 个分层模型项"); - return layerItems; + LogManager.Info($"[SimplifiedModelSplitter] 保存可见性状态完成,记录了 {visibilityState.Count} 个顶级项目"); } catch (Exception ex) { - LogManager.Error($"[SimplifiedModelSplitter] 获取分层模型项失败: {ex.Message}"); - LogManager.Error($"[SimplifiedModelSplitter] 异常堆栈: {ex.StackTrace}"); - return new ModelItemCollection(); + LogManager.Error($"[SimplifiedModelSplitter] 保存可见性状态失败: {ex.Message}"); } + + return visibilityState; } /// @@ -1598,42 +1618,6 @@ namespace NavisworksTransport return false; } - /// - /// 保存当前可见性状态 - /// - private Dictionary SaveVisibilityState(Document document) - { - var visibilityState = new Dictionary(); - - try - { - // 这里需要保存所有模型项的可见性状态 - // 简化实现:记录隐藏的项目 - var allItems = new ModelItemCollection(); - allItems.AddRange(document.Models.RootItemDescendantsAndSelf); - - foreach (ModelItem item in allItems) - { - try - { - // Navisworks中检查项目是否隐藏的方法 - visibilityState[item] = !item.IsHidden; - } - catch - { - // 如果无法获取状态,默认为可见 - visibilityState[item] = true; - } - } - } - catch (Exception ex) - { - LogManager.Error($"[SimplifiedModelSplitter] 保存可见性状态失败: {ex.Message}"); - } - - return visibilityState; - } - /// /// 恢复可见性状态 /// @@ -1701,84 +1685,6 @@ namespace NavisworksTransport } } - /// - /// 隐藏除指定项目外的其他所有项目 - 使用成熟的可见性控制模式 - /// - private void HideOtherItems(Document document, ModelItemCollection keepVisible) - { - try - { - LogManager.Info($"[SimplifiedModelSplitter] 开始隐藏其他项目,保持可见: {keepVisible.Count} 个项目"); - - // 获取所有项目 - 使用安全的AddRange方法 - var allItems = new ModelItemCollection(); - allItems.AddRange(document.Models.RootItemDescendantsAndSelf); - LogManager.Info($"[SimplifiedModelSplitter] 总共 {allItems.Count} 个模型项目"); - - // 先重置所有项目为可见状态,确保从干净状态开始 - document.Models.ResetAllHidden(); - LogManager.Info("[SimplifiedModelSplitter] 已重置所有项目为可见状态"); - - // 收集需要隐藏的项目 - 不在keepVisible集合中的项目 - var itemsToHide = new ModelItemCollection(); - - foreach (ModelItem item in allItems) - { - try - { - // 检查该项目是否在keepVisible集合中 - bool shouldKeepVisible = false; - foreach (ModelItem visibleItem in keepVisible) - { - if (item.Equals(visibleItem)) - { - shouldKeepVisible = true; - break; - } - } - - // 如果不在保持可见的集合中,则需要隐藏 - if (!shouldKeepVisible) - { - itemsToHide.Add(item); - } - } - catch (Exception ex) - { - LogManager.Warning($"[SimplifiedModelSplitter] 检查项目可见性时出错: {ex.Message}"); - } - } - - LogManager.Info($"[SimplifiedModelSplitter] 需要隐藏 {itemsToHide.Count} 个项目"); - - // 执行隐藏操作 - 使用成熟的SetHidden方法 - if (itemsToHide.Count > 0) - { - document.Models.SetHidden(itemsToHide, true); - LogManager.Info($"[SimplifiedModelSplitter] 成功隐藏 {itemsToHide.Count} 个项目"); - } - else - { - LogManager.Info("[SimplifiedModelSplitter] 没有项目需要隐藏"); - } - } - catch (Exception ex) - { - LogManager.Error($"[SimplifiedModelSplitter] 隐藏其他项目失败: {ex.Message}"); - - // 异常处理:确保至少显示所有项目 - try - { - document.Models.ResetAllHidden(); - LogManager.Info("[SimplifiedModelSplitter] 异常恢复:重置为全部可见"); - } - catch (Exception resetEx) - { - LogManager.Error($"[SimplifiedModelSplitter] 异常恢复也失败: {resetEx.Message}"); - } - } - } - /// /// 简化的环境诊断方法 - 快速检查API是否可用 /// diff --git a/src/Utils/NavisworksFileExporter.cs b/src/Utils/NavisworksFileExporter.cs deleted file mode 100644 index b7650f9..0000000 --- a/src/Utils/NavisworksFileExporter.cs +++ /dev/null @@ -1,1014 +0,0 @@ -using Autodesk.Navisworks.Api; -using System; -using System.IO; -using System.Threading.Tasks; -using System.Collections.Generic; -using System.Linq; - -namespace NavisworksTransport -{ - /// - /// Navisworks文件导出器 - 负责将模型元素导出为独立的Navisworks文件 - /// - public class NavisworksFileExporter - { - #region 枚举和常量 - - /// - /// 导出策略枚举 - /// - public enum ExportStrategy - { - VisibilityControl, // 通过可见性控制 - SelectionBased, // 基于选择集 - CopyToNewDocument // 复制到新文档 - } - - /// - /// 导出配置 - /// - public class ExportConfiguration - { - public ExportStrategy Strategy { get; set; } = ExportStrategy.VisibilityControl; - public bool PreserveViewpoints { get; set; } = false; - public bool PreserveAnimations { get; set; } = false; - public bool PreserveClashTests { get; set; } = false; - public bool CompressOutput { get; set; } = true; - public string FileFormat { get; set; } = "nwd"; // nwd, nwf, nwc - public int TimeoutSeconds { get; set; } = 300; - public bool CreateBackup { get; set; } = true; - } - - #endregion - - #region 事件定义 - - public event EventHandler StatusChanged; - public event EventHandler ProgressChanged; - public event EventHandler ErrorOccurred; - - #endregion - - #region 私有字段 - - private readonly VisibilityManager _visibilityManager; - private bool _isExporting = false; - - #endregion - - #region 构造函数 - - public NavisworksFileExporter() - { - _visibilityManager = new VisibilityManager(); - LogManager.Info("[FileExporter] Navisworks文件导出器已初始化"); - } - - #endregion - - #region 公共方法 - - /// - /// 异步导出模型元素到文件 - /// - /// 要导出的模型元素 - /// 输出文件路径 - /// 导出配置 - /// 导出是否成功 - public async Task ExportModelItemsAsync(ModelItemCollection items, string outputPath, ExportConfiguration config = null) - { - if (_isExporting) - { - throw new InvalidOperationException("导出操作正在进行中"); - } - - try - { - _isExporting = true; - config = config ?? new ExportConfiguration(); - - LogManager.WriteSessionSeparator(); - LogManager.Info($"[FileExporter] ========== 开始文件导出 =========="); - LogManager.Info($"[FileExporter] 元素数量: {items.Count}"); - LogManager.Info($"[FileExporter] 输出路径: {outputPath}"); - LogManager.Info($"[FileExporter] 导出策略: {config.Strategy}"); - LogManager.Info($"[FileExporter] 文件格式: {config.FileFormat}"); - - OnStatusChanged($"开始导出 {items.Count} 个元素到 {Path.GetFileName(outputPath)}"); - - // 记录系统状态 - LogManager.Info($"[FileExporter] 导出前内存使用: {GC.GetTotalMemory(false) / 1024 / 1024} MB"); - - // 验证输入参数 - LogManager.Info("[FileExporter] 开始验证输入参数..."); - ValidateExportParameters(items, outputPath); - LogManager.Info("[FileExporter] 输入参数验证完成"); - - // 创建输出目录 - LogManager.Info("[FileExporter] 开始创建输出目录..."); - EnsureOutputDirectory(outputPath); - LogManager.Info("[FileExporter] 输出目录创建完成"); - - // 使用分层导出逻辑(参考保存当前选择项的验证方法) - LogManager.Info("[FileExporter] 开始分层导出逻辑..."); - bool success = await ExportWithLayerLogicAsync(items, outputPath, config); - LogManager.Info($"[FileExporter] 分层导出完成,结果: {success}"); - - if (success) - { - LogManager.Info($"[FileExporter] 导出成功: {outputPath}"); - OnStatusChanged("导出完成"); - } - else - { - LogManager.Error($"[FileExporter] 导出失败: {outputPath}"); - OnStatusChanged("导出失败"); - } - - return success; - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 导出异常: {ex.Message}"); - OnErrorOccurred(ex); - return false; - } - finally - { - _isExporting = false; - } - } - - /// - /// 使用分层逻辑导出(参考保存当前选择项的验证方法) - /// 业务逻辑:选择当前层,隐藏其他层,导出,恢复隐藏 - /// - private async Task ExportWithLayerLogicAsync(ModelItemCollection items, string outputPath, ExportConfiguration config) - { - try - { - LogManager.Info("[FileExporter] 开始分层导出逻辑"); - - var document = Application.ActiveDocument; - if (document?.Models?.Count == 0) - { - LogManager.Error("[FileExporter] 没有活动文档或模型"); - return false; - } - - // 保存当前选择状态 - var originalSelection = new List(); - foreach (ModelItem item in document.CurrentSelection.SelectedItems) - { - originalSelection.Add(item); - } - LogManager.Info($"[FileExporter] 已保存原始选择状态,包含 {originalSelection.Count} 个元素"); - - try - { - // 1. 收集所有顶级节点(参考保存当前选择项的方法) - var allTopLevelItems = new List(); - foreach (Model model in document.Models) - { - foreach (ModelItem topLevelItem in model.RootItem.Children) - { - allTopLevelItems.Add(topLevelItem); - } - } - LogManager.Info($"[FileExporter] 收集到 {allTopLevelItems.Count} 个顶级节点"); - - // 2. 智能隐藏策略:隐藏不包含目标元素的顶级节点 - var itemsToHide = new ModelItemCollection(); - int hiddenCount = 0; - - foreach (ModelItem topLevelItem in allTopLevelItems) - { - bool shouldKeepTopLevel = false; - - // 检查是否有任何目标元素属于这个顶级节点 - foreach (ModelItem targetItem in items) - { - var current = targetItem; - while (current != null) - { - if (current == topLevelItem) - { - shouldKeepTopLevel = true; - LogManager.Info($"[FileExporter] 顶级节点 {topLevelItem.DisplayName} 包含目标元素,保持可见"); - break; - } - current = current.Parent; - } - if (shouldKeepTopLevel) break; - } - - // 如果这个顶级节点不需要保持可见,则隐藏它 - if (!shouldKeepTopLevel) - { - try - { - itemsToHide.Add(topLevelItem); - hiddenCount++; - LogManager.Info($"[FileExporter] 隐藏顶级节点: {topLevelItem.DisplayName}"); - } - catch (Exception ex) - { - LogManager.Warning($"[FileExporter] 添加隐藏项目失败: {topLevelItem.DisplayName} - {ex.Message}"); - } - } - } - - // 3. 执行隐藏操作 - if (itemsToHide.Count > 0) - { - try - { - document.Models.SetHidden(itemsToHide, true); - LogManager.Info($"[FileExporter] 成功隐藏 {hiddenCount} 个顶级节点"); - } - catch (Exception ex) - { - LogManager.Warning($"[FileExporter] 隐藏操作失败: {ex.Message}"); - } - } - - // 4. 确保选择目标元素 - document.CurrentSelection.Clear(); - foreach (ModelItem item in items) - { - try - { - document.CurrentSelection.Add(item); - } - catch (Exception ex) - { - LogManager.Warning($"[FileExporter] 添加选择元素失败: {item.DisplayName} - {ex.Message}"); - } - } - LogManager.Info($"[FileExporter] 已选择 {items.Count} 个目标元素"); - - // 5. 使用正确的导出方法 - OnStatusChanged("正在保存文件..."); - LogManager.Info("[FileExporter] 开始调用SaveDocument..."); - bool saveSuccess = SaveDocument(document, outputPath, config); - LogManager.Info($"[FileExporter] SaveDocument调用结果: {saveSuccess}"); - - // 6. 恢复所有隐藏项目的可见性(参考保存当前选择项的方法) - try - { - if (document?.Models != null && itemsToHide.Count > 0) - { - // 恢复所有顶级节点的可见性 - var allItems = new ModelItemCollection(); - foreach (Model model in document.Models) - { - foreach (ModelItem item in model.RootItem.Children) - { - allItems.Add(item); - } - } - - if (allItems.Count > 0) - { - document.Models.SetHidden(allItems, false); - LogManager.Info("[FileExporter] 已恢复所有项目可见性"); - } - } - } - catch (Exception ex) - { - LogManager.Warning($"[FileExporter] 恢复可见性失败: {ex.Message}"); - } - - return saveSuccess; - } - finally - { - // 7. 恢复原始选择 - try - { - document.CurrentSelection.Clear(); - foreach (ModelItem item in originalSelection) - { - try - { - document.CurrentSelection.Add(item); - } - catch (Exception ex) - { - LogManager.Warning($"[FileExporter] 恢复选择项时出错: {ex.Message}"); - } - } - LogManager.Info("[FileExporter] 已恢复原始选择"); - } - catch (Exception ex) - { - LogManager.Warning($"[FileExporter] 恢复选择失败: {ex.Message}"); - } - } - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 分层导出逻辑异常: {ex.Message}"); - throw; - } - } - - /// - /// 同步导出模型元素到文件 - /// - /// 要导出的模型元素 - /// 输出文件路径 - /// 导出配置 - /// 导出是否成功 - public bool ExportModelItems(ModelItemCollection items, string outputPath, ExportConfiguration config = null) - { - try - { - var task = ExportModelItemsAsync(items, outputPath, config); - task.Wait(); - return task.Result; - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 同步导出失败: {ex.Message}"); - return false; - } - } - - /// - /// 批量导出多个分组 - /// - /// 导出任务列表 - /// 导出配置 - /// 导出结果列表 - public async Task> BatchExportAsync(List exportTasks, ExportConfiguration config = null) - { - try - { - LogManager.Info($"[FileExporter] 开始批量导出,任务数量: {exportTasks.Count}"); - - var results = new List(); - int completedCount = 0; - - foreach (var task in exportTasks) - { - try - { - OnStatusChanged($"正在导出: {task.LayerName} ({completedCount + 1}/{exportTasks.Count})"); - OnProgressChanged((int)((double)completedCount / exportTasks.Count * 100)); - - bool success = await ExportModelItemsAsync(task.Items, task.OutputPath, config); - - var result = new ExportResult - { - LayerName = task.LayerName, - OutputPath = task.OutputPath, - Success = success, - ItemCount = task.Items.Count, - ProcessTime = DateTime.Now - }; - - if (success && File.Exists(task.OutputPath)) - { - result.FileSizeBytes = new FileInfo(task.OutputPath).Length; - } - else if (!success) - { - result.ErrorMessage = "导出失败"; - } - - results.Add(result); - completedCount++; - - LogManager.Info($"[FileExporter] 批量导出进度: {completedCount}/{exportTasks.Count}"); - } - catch (Exception ex) - { - var errorResult = new ExportResult - { - LayerName = task.LayerName, - OutputPath = task.OutputPath, - Success = false, - ErrorMessage = ex.Message, - ItemCount = task.Items.Count, - ProcessTime = DateTime.Now - }; - results.Add(errorResult); - - LogManager.Error($"[FileExporter] 批量导出任务失败: {task.LayerName}, 错误: {ex.Message}"); - } - } - - OnProgressChanged(100); - OnStatusChanged($"批量导出完成,成功: {results.Count(r => r.Success)}, 失败: {results.Count(r => !r.Success)}"); - - LogManager.Info($"[FileExporter] 批量导出完成,总计: {results.Count}, 成功: {results.Count(r => r.Success)}"); - return results; - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 批量导出异常: {ex.Message}"); - throw; - } - } - - #endregion - - #region 数据结构 - - /// - /// 导出任务 - /// - public class ExportTask - { - public string LayerName { get; set; } - public ModelItemCollection Items { get; set; } - public string OutputPath { get; set; } - } - - /// - /// 导出结果 - /// - public class ExportResult - { - public string LayerName { get; set; } - public string OutputPath { get; set; } - public bool Success { get; set; } - public string ErrorMessage { get; set; } - public int ItemCount { get; set; } - public long FileSizeBytes { get; set; } - public DateTime ProcessTime { get; set; } - } - - #endregion - - #region 私有方法 - 导出执行 - - private async Task ExecuteExportAsync(ModelItemCollection items, string outputPath, ExportConfiguration config) - { - switch (config.Strategy) - { - case ExportStrategy.VisibilityControl: - return await ExportByVisibilityControlAsync(items, outputPath, config); - - case ExportStrategy.SelectionBased: - return await ExportBySelectionAsync(items, outputPath, config); - - case ExportStrategy.CopyToNewDocument: - return await ExportByCopyToNewDocumentAsync(items, outputPath, config); - - default: - throw new NotSupportedException($"不支持的导出策略: {config.Strategy}"); - } - } - - private Task ExportByVisibilityControlAsync(ModelItemCollection items, string outputPath, ExportConfiguration config) - { - try - { - LogManager.Info("[FileExporter] 使用纯选择集策略导出(完全避免可见性操作)"); - - var document = Application.ActiveDocument; - if (document == null) - { - throw new InvalidOperationException("没有活动的Navisworks文档"); - } - - // 关键修复:完全避免任何可见性操作,只使用选择集 - try - { - OnStatusChanged("正在准备导出..."); - LogManager.Info("[FileExporter] 开始纯选择集导出流程"); - - // 保存原始选择状态 - var originalSelection = new ModelItemCollection(); - originalSelection.CopyFrom(document.CurrentSelection.SelectedItems); - LogManager.Info($"[FileExporter] 已保存原始选择状态,包含 {originalSelection.Count} 个元素"); - - try - { - // 设置新的选择集 - OnStatusChanged("正在设置选择集..."); - LogManager.Info("[FileExporter] 清除当前选择..."); - document.CurrentSelection.Clear(); - - LogManager.Info($"[FileExporter] 开始逐个添加 {items.Count} 个目标元素到选择集..."); - - // 关键修复:逐个添加元素,避免批量操作导致的崩溃 - int addedCount = 0; - foreach (ModelItem item in items) - { - try - { - document.CurrentSelection.Add(item); - addedCount++; - - // 每添加50个元素记录一次进度 - if (addedCount % 50 == 0) - { - LogManager.Info($"[FileExporter] 已添加 {addedCount}/{items.Count} 个元素到选择集"); - } - } - catch (Exception addEx) - { - LogManager.Warning($"[FileExporter] 添加元素到选择集失败: {addEx.Message}"); - // 继续处理其他元素,不因单个元素失败而中断 - } - } - - LogManager.Info($"[FileExporter] 选择集添加完成,成功添加 {addedCount}/{items.Count} 个元素"); - - LogManager.Info("[FileExporter] 选择集设置完成"); - - // 等待状态稳定 - LogManager.Info("[FileExporter] 等待系统稳定..."); - System.Threading.Thread.Sleep(200); - - // 直接导出文件,不进行任何可见性操作 - OnStatusChanged("正在保存文件..."); - LogManager.Info("[FileExporter] 开始保存文档..."); - bool saveSuccess = SaveDocument(document, outputPath, config); - LogManager.Info($"[FileExporter] 文档保存结果: {saveSuccess}"); - - return Task.FromResult(saveSuccess); - } - finally - { - // 恢复原始选择状态 - try - { - LogManager.Info("[FileExporter] 开始恢复原始选择状态..."); - document.CurrentSelection.Clear(); - if (originalSelection.Count > 0) - { - document.CurrentSelection.AddRange(originalSelection); - LogManager.Info($"[FileExporter] 已恢复 {originalSelection.Count} 个原始选择元素"); - } - else - { - LogManager.Info("[FileExporter] 原始选择为空,保持清空状态"); - } - } - catch (Exception restoreEx) - { - LogManager.Warning($"[FileExporter] 恢复原始选择失败: {restoreEx.Message}"); - } - } - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 选择集导出过程中发生异常: {ex.Message}"); - LogManager.Error($"[FileExporter] 异常堆栈: {ex.StackTrace}"); - - // 只进行最安全的清理操作 - try - { - document.CurrentSelection.Clear(); - LogManager.Info("[FileExporter] 异常恢复:已清除选择集"); - } - catch (Exception safeEx) - { - LogManager.Warning($"[FileExporter] 异常恢复中的安全操作也失败: {safeEx.Message}"); - } - throw; - } - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 纯选择集导出失败: {ex.Message}"); - throw; - } - } - - private Task ExportBySelectionAsync(ModelItemCollection items, string outputPath, ExportConfiguration config) - { - try - { - LogManager.Info("[FileExporter] 使用选择集策略导出"); - - var document = Application.ActiveDocument; - if (document == null) - { - throw new InvalidOperationException("没有活动的Navisworks文档"); - } - - // 保存当前选择 - var originalSelection = new ModelItemCollection(); - originalSelection.CopyFrom(document.CurrentSelection.SelectedItems); - - try - { - // 设置新的选择集 - OnStatusChanged("正在设置选择集..."); - document.CurrentSelection.Clear(); - document.CurrentSelection.AddRange(items); - - // 等待选择更新 - System.Threading.Thread.Sleep(200); - - // 导出选中的元素 - OnStatusChanged("正在导出选中元素..."); - bool exportSuccess = ExportSelectedItems(document, outputPath, config); - - return Task.FromResult(exportSuccess); - } - finally - { - // 恢复原始选择 - document.CurrentSelection.Clear(); - if (originalSelection.Count > 0) - { - document.CurrentSelection.AddRange(originalSelection); - } - } - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 选择集导出失败: {ex.Message}"); - throw; - } - } - - private async Task ExportByCopyToNewDocumentAsync(ModelItemCollection items, string outputPath, ExportConfiguration config) - { - try - { - LogManager.Info("[FileExporter] 使用新文档策略导出"); - - // 注意:Navisworks API不直接支持创建新文档并复制元素 - // 这里使用可见性控制作为替代方案 - LogManager.Warning("[FileExporter] 新文档策略不被直接支持,使用可见性控制替代"); - - return await ExportByVisibilityControlAsync(items, outputPath, config); - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 新文档导出失败: {ex.Message}"); - throw; - } - } - - #endregion - - #region 私有方法 - 文件操作 - - private bool SaveDocument(Document document, string outputPath, ExportConfiguration config) - { - try - { - LogManager.Info($"[FileExporter] 开始保存文档到: {outputPath}"); - - // 创建备份 - if (config.CreateBackup && File.Exists(outputPath)) - { - string backupPath = outputPath + ".backup"; - File.Copy(outputPath, backupPath, true); - LogManager.Info($"[FileExporter] 已创建备份文件: {backupPath}"); - } - - // 使用正确的ExportToNwd API(参考文档5.2节) - try - { - LogManager.Info("[FileExporter] 开始使用ExportToNwd API保存文档"); - - // 确保文档处于稳定状态 - if (document.Models.Count == 0) - { - throw new InvalidOperationException("文档中没有模型数据"); - } - - // 等待一小段时间确保状态稳定 - System.Threading.Thread.Sleep(100); - - // 创建导出选项 - 参考保存当前选择项的正确做法 - var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions(); - exportOptions.ExcludeHiddenItems = true; // 只导出可见项目 - exportOptions.EmbedXrefs = false; - exportOptions.PreventObjectPropertyExport = false; - - // 使用ExportToNwd API导出 - document.ExportToNwd(outputPath, exportOptions); - - LogManager.Info("[FileExporter] ExportToNwd API调用完成"); - - // 验证文件是否成功保存 - if (File.Exists(outputPath)) - { - var fileInfo = new FileInfo(outputPath); - if (fileInfo.Length > 0) - { - LogManager.Info($"[FileExporter] 文档保存成功: {outputPath}, 大小: {fileInfo.Length} 字节"); - return true; - } - else - { - LogManager.Warning($"[FileExporter] 保存的文件大小为0: {outputPath}"); - File.Delete(outputPath); // 删除空文件 - return false; - } - } - else - { - LogManager.Warning($"[FileExporter] 保存后文件不存在: {outputPath}"); - return false; - } - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] ExportToNwd保存失败: {ex.Message}"); - return false; - } - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 保存文档异常: {ex.Message}"); - return false; - } - } - - private bool ExportSelectedItems(Document document, string outputPath, ExportConfiguration config) - { - try - { - // 对于选择集导出,我们仍然需要使用可见性控制 - // 因为Navisworks不支持直接导出选中的元素 - - var selectedItems = document.CurrentSelection.SelectedItems; - var task = ExportByVisibilityControlAsync(selectedItems, outputPath, config); - task.Wait(); - return task.Result; - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 导出选中元素失败: {ex.Message}"); - return false; - } - } - - private void SaveAsNwfFormat(Document document, string outputPath) - { - try - { - // NWF是Navisworks的工作文件格式 - // 需要使用COM API进行特殊处理 - LogManager.Info("[FileExporter] 保存为NWF格式"); - document.SaveFile(outputPath); - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 保存NWF格式失败: {ex.Message}"); - throw; - } - } - - private void SaveAsNwcFormat(Document document, string outputPath) - { - try - { - // NWC是Navisworks的缓存文件格式 - LogManager.Info("[FileExporter] 保存为NWC格式"); - document.SaveFile(outputPath); - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 保存NWC格式失败: {ex.Message}"); - throw; - } - } - - #endregion - - #region 私有方法 - 可见性状态管理 - - private Dictionary SaveCurrentVisibilityState() - { - try - { - LogManager.Info("[FileExporter] 保存当前可见性状态"); - - var visibilityState = new Dictionary(); - var document = Application.ActiveDocument; - - if (document?.Models != null) - { - // 安全获取所有模型项 - 使用AddRange避免挂起 - var allItems = new ModelItemCollection(); - allItems.AddRange(document.Models.RootItemDescendantsAndSelf); - - // 遍历ModelItemCollection而不是直接遍历RootItemDescendantsAndSelf - foreach (ModelItem item in allItems) - { - try - { - visibilityState[item] = !item.IsHidden; - } - catch - { - // 忽略无法访问的元素 - } - } - } - - LogManager.Info($"[FileExporter] 已保存 {visibilityState.Count} 个元素的可见性状态"); - return visibilityState; - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 保存可见性状态失败: {ex.Message}"); - return new Dictionary(); - } - } - - private void RestoreVisibilityState(Dictionary visibilityState) - { - try - { - LogManager.Info("[FileExporter] 恢复可见性状态"); - - if (visibilityState == null || visibilityState.Count == 0) - { - LogManager.Warning("[FileExporter] 没有可见性状态需要恢复"); - return; - } - - // 直接执行,避免异步复杂性(.NET Framework 4.6兼容) - var itemsToShow = new ModelItemCollection(); - var itemsToHide = new ModelItemCollection(); - - foreach (var kvp in visibilityState) - { - try - { - if (kvp.Value) // 原来是可见的 - { - itemsToShow.Add(kvp.Key); - } - else // 原来是隐藏的 - { - itemsToHide.Add(kvp.Key); - } - } - catch - { - // 忽略无法访问的元素 - } - } - - // 批量恢复可见性 - 使用Document的SetHidden方法 - var document = Application.ActiveDocument; - if (document != null) - { - if (itemsToShow.Count > 0) - { - document.Models.SetHidden(itemsToShow, false); - } - - if (itemsToHide.Count > 0) - { - document.Models.SetHidden(itemsToHide, true); - } - } - - LogManager.Info("[FileExporter] 可见性状态恢复完成"); - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 恢复可见性状态失败: {ex.Message}"); - } - } - - #endregion - - #region 私有方法 - 验证和辅助 - - private void ValidateExportParameters(ModelItemCollection items, string outputPath) - { - if (items == null || items.Count == 0) - { - throw new ArgumentException("要导出的模型元素集合不能为空", nameof(items)); - } - - if (string.IsNullOrEmpty(outputPath)) - { - throw new ArgumentException("输出路径不能为空", nameof(outputPath)); - } - - string directory = Path.GetDirectoryName(outputPath); - if (!string.IsNullOrEmpty(directory) && !Directory.Exists(Path.GetDirectoryName(directory))) - { - throw new DirectoryNotFoundException($"输出目录的父目录不存在: {Path.GetDirectoryName(directory)}"); - } - - var document = Application.ActiveDocument; - if (document?.Models == null || document.Models.Count == 0) - { - throw new InvalidOperationException("当前没有打开的Navisworks文档"); - } - } - - private void EnsureOutputDirectory(string outputPath) - { - string directory = Path.GetDirectoryName(outputPath); - if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - LogManager.Info($"[FileExporter] 已创建输出目录: {directory}"); - } - } - - /// - /// 检查一个模型项或其子项是否包含目标元素中的任何一个 - /// - /// 要检查的根模型项 - /// 目标元素集合 - /// 如果包含则返回true - private bool ContainsAnyTargetItem(ModelItem rootItem, ModelItemCollection targetItems) - { - try - { - // 首先检查根项目本身 - if (targetItems.Contains(rootItem)) - { - return true; - } - - // 递归检查子项目(使用深度优先搜索,但限制深度避免栈溢出) - return ContainsAnyTargetItemRecursive(rootItem, targetItems, 0, 10); - } - catch (Exception ex) - { - LogManager.Error($"[FileExporter] 检查目标元素时出错: {ex.Message}"); - // 出错时保守处理,假设包含目标元素 - return true; - } - } - - /// - /// 递归检查子项目,带深度限制 - /// - /// 当前检查的项目 - /// 目标元素集合 - /// 当前深度 - /// 最大深度 - /// 如果包含则返回true - private bool ContainsAnyTargetItemRecursive(ModelItem item, ModelItemCollection targetItems, int currentDepth, int maxDepth) - { - try - { - // 防止递归过深 - if (currentDepth > maxDepth) - { - return false; - } - - // 检查当前项目的所有子项 - if (item.Children != null) - { - foreach (ModelItem child in item.Children) - { - // 检查子项目本身 - if (targetItems.Contains(child)) - { - return true; - } - - // 递归检查子项目的子项 - if (ContainsAnyTargetItemRecursive(child, targetItems, currentDepth + 1, maxDepth)) - { - return true; - } - } - } - - return false; - } - catch (Exception) - { - // 出错时保守处理 - return false; - } - } - - #endregion - - #region 事件触发方法 - - protected virtual void OnStatusChanged(string status) - { - StatusChanged?.Invoke(this, status); - } - - protected virtual void OnProgressChanged(int progress) - { - ProgressChanged?.Invoke(this, progress); - } - - protected virtual void OnErrorOccurred(Exception ex) - { - ErrorOccurred?.Invoke(this, ex); - } - - #endregion - } -} \ No newline at end of file