From 034ca80db2e563a3454d70e1216f7d023b0a09fd Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Mon, 15 Sep 2025 19:36:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BF=9D=E5=AD=98=E9=80=89?= =?UTF-8?q?=E6=8B=A9=E9=9B=86=E4=BD=BF=E7=94=A8=E6=97=A7=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E5=BC=95=E8=B5=B7=E7=9A=84=E4=BF=9D=E5=AD=98=E6=95=B4=E4=B8=AA?= =?UTF-8?q?=E5=88=86=E5=B1=82=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ViewModels/LayerManagementViewModel.cs | 323 ++++++++++-------- 1 file changed, 178 insertions(+), 145 deletions(-) diff --git a/src/UI/WPF/ViewModels/LayerManagementViewModel.cs b/src/UI/WPF/ViewModels/LayerManagementViewModel.cs index 4fbdb87..e5c4a3a 100644 --- a/src/UI/WPF/ViewModels/LayerManagementViewModel.cs +++ b/src/UI/WPF/ViewModels/LayerManagementViewModel.cs @@ -1840,35 +1840,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels LogManager.Info($"[LayerManagementViewModel] 开始保存选中项目到: {saveFilePath}"); LogManager.Info($"[LayerManagementViewModel] 保存 {originalSelection.Count} 个选中节点及其所有子项"); - // 4. 使用基于多选节点的保存逻辑 + // 4. 使用借鉴自 ModelSplitterManager.ExportLayerToNwd 的精确隔离逻辑 bool exportResult = false; string errorMessage = ""; try { - // 收集所有需要显示的节点(选中的节点和它们的祖先节点) - var nodesToKeepVisible = new HashSet(); - - // 对于每个选中的节点,收集它和它的所有祖先节点 + // 收集要导出的项目(包含子节点) + var itemsToExport = new List(); + foreach (var selectedItem in originalSelection) { // 添加选中节点本身 - nodesToKeepVisible.Add(selectedItem); - LogManager.Info($"[LayerManagementViewModel] 添加选中节点到可见列表: {selectedItem.DisplayName}"); - - // 添加所有祖先节点,确保选中节点的路径可见 - var current = selectedItem.Parent; - while (current != null) - { - nodesToKeepVisible.Add(current); - LogManager.Info($"[LayerManagementViewModel] 添加祖先节点到可见列表: {current.DisplayName}"); - current = current.Parent; - } + itemsToExport.Add(selectedItem); + LogManager.Info($"[LayerManagementViewModel] 添加选中节点到导出列表: {selectedItem.DisplayName}"); // 添加所有子节点(如果用户开启了包含子节点选项) if (IncludeChildNodes) { - // 使用正确的Navisworks API遍历子节点 try { // 使用DescendantsAndSelf来获取所有后代节点 @@ -1877,7 +1866,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels foreach (ModelItem child in childItems) { - nodesToKeepVisible.Add(child); + itemsToExport.Add(child); childCount++; } @@ -1890,141 +1879,81 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } - LogManager.Info($"[LayerManagementViewModel] 总共需要保持可见的节点数量: {nodesToKeepVisible.Count}"); + LogManager.Info($"[LayerManagementViewModel] 总共需要导出的节点数量: {itemsToExport.Count}"); - // 使用正确的Navisworks API收集顶级节点 - // 根据示例,这是正确的方式来获取所有顶级模型项 - var allTopLevelItems = new List(); - - // 使用RootItemDescendantsAndSelf,但只取第一级子项 - foreach (Model model in document.Models) - { - foreach (ModelItem topLevelItem in model.RootItem.Children) - { - allTopLevelItems.Add(topLevelItem); - } - } - - LogManager.Info($"[LayerManagementViewModel] 收集到 {allTopLevelItems.Count} 个顶级节点"); - - // 更智能的隐藏策略: - // 1. 如果选中节点包含某个顶级节点或其子节点,则该顶级节点保持可见 - // 2. 否则隐藏整个顶级节点分支 - var itemsToHide = new ModelItemCollection(); - int hiddenCount = 0; - - foreach (ModelItem topLevelItem in allTopLevelItems) - { - bool shouldKeepTopLevel = false; - - // 检查这个顶级节点或其任何子节点是否需要保持可见 - if (nodesToKeepVisible.Contains(topLevelItem)) - { - shouldKeepTopLevel = true; - LogManager.Info($"[LayerManagementViewModel] 顶级节点 {topLevelItem.DisplayName} 本身被选中,保持可见"); - } - else - { - // 检查是否有任何选中节点是这个顶级节点的后代 - foreach (var selectedItem in originalSelection) - { - var current = selectedItem; - while (current != null) - { - if (current == topLevelItem) - { - shouldKeepTopLevel = true; - LogManager.Info($"[LayerManagementViewModel] 顶级节点 {topLevelItem.DisplayName} 包含选中节点,保持可见"); - break; - } - current = current.Parent; - } - if (shouldKeepTopLevel) break; - } - } - - // 如果这个顶级节点不需要保持可见,则隐藏它 - if (!shouldKeepTopLevel) - { - try - { - itemsToHide.Add(topLevelItem); - hiddenCount++; - LogManager.Info($"[LayerManagementViewModel] 隐藏顶级节点: {topLevelItem.DisplayName}"); - } - catch (Exception ex) - { - LogManager.Warning($"[LayerManagementViewModel] 添加隐藏项目失败: {topLevelItem.DisplayName} - {ex.Message}"); - } - } - } - - // 执行隐藏操作 - if (itemsToHide.Count > 0) + // 核心修复:使用与 ModelSplitterManager.ExportLayerToNwd 相同的精确隔离逻辑 + // 在主线程中执行 Navisworks API 调用 + System.Windows.Application.Current.Dispatcher.Invoke(() => { try { - document.Models.SetHidden(itemsToHide, true); - LogManager.Info($"[LayerManagementViewModel] 成功隐藏 {hiddenCount} 个节点,保留 {nodesToKeepVisible.Count} 个选中节点及其相关节点可见"); + LogManager.Info($"[LayerManagementViewModel] 在主线程中执行导出操作"); + + // 保存当前可见性状态 + LogManager.Info($"[LayerManagementViewModel] 开始保存当前可见性状态"); + var originalVisibilityState = SaveCurrentVisibilityState(document); + LogManager.Info($"[LayerManagementViewModel] 已保存可见性状态"); + + try + { + // 使用 VisibilityHelper.IsolateSpecificItems 精确隔离显示 + // 这个方法已经在分层导出中验证有效,不会包含额外的祖先节点 + LogManager.Info($"[LayerManagementViewModel] 准备隔离显示 {itemsToExport.Count} 个节点"); + + // 将 List 转换为 ModelItemCollection + var itemsToIsolate = new ModelItemCollection(); + foreach (var item in itemsToExport) + { + itemsToIsolate.Add(item); + } + + bool isolateSuccess = VisibilityHelper.IsolateSpecificItems(itemsToIsolate); + + if (!isolateSuccess) + { + throw new InvalidOperationException("隔离显示失败"); + } + + LogManager.Info($"[LayerManagementViewModel] 隔离显示成功"); + + // 创建导出选项 - 使用用户配置的参数 + var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions + { + ExcludeHiddenItems = true, // 只导出可见项目(选中节点及其子项) + EmbedXrefs = EmbedXrefs, + PreventObjectPropertyExport = PreventObjectPropertyExport + }; + + LogManager.Info($"[LayerManagementViewModel] SaveSelectedItems导出选项: EmbedXrefs={exportOptions.EmbedXrefs}, PreventObjectPropertyExport={exportOptions.PreventObjectPropertyExport}"); + LogManager.Info("[LayerManagementViewModel] 开始调用ExportToNwd API"); + + // 使用ExportToNwd API + document.ExportToNwd(saveFilePath, exportOptions); + + exportResult = true; + LogManager.Info("[LayerManagementViewModel] ExportToNwd API调用完成"); + } + finally + { + // 恢复原始可见性状态 + try + { + RestoreVisibilityState(document, originalVisibilityState); + LogManager.Info("[LayerManagementViewModel] 已恢复原始可见性状态"); + } + catch (Exception restoreEx) + { + LogManager.Error($"[LayerManagementViewModel] 恢复可见性失败: {restoreEx.Message}"); + } + } } catch (Exception ex) { - LogManager.Warning($"[LayerManagementViewModel] 隐藏操作失败: {ex.Message}"); + LogManager.Error($"[LayerManagementViewModel] 主线程导出异常: {ex.Message}", ex); + errorMessage = ex.Message; + exportResult = false; } - } - - // 确保选中所有目标节点 - document.CurrentSelection.Clear(); - foreach (var selectedItem in originalSelection) - { - document.CurrentSelection.Add(selectedItem); - } - LogManager.Info($"[LayerManagementViewModel] 已重新选择 {originalSelection.Count} 个目标节点"); - - // 创建导出选项 - 使用用户配置的参数 - var exportOptions = new Autodesk.Navisworks.Api.NwdExportOptions - { - ExcludeHiddenItems = true, // 只导出可见项目(选中节点及其子项) - EmbedXrefs = EmbedXrefs, - PreventObjectPropertyExport = PreventObjectPropertyExport - }; - - LogManager.Info($"[LayerManagementViewModel] SaveSelectedItems导出选项: EmbedXrefs={exportOptions.EmbedXrefs}, PreventObjectPropertyExport={exportOptions.PreventObjectPropertyExport}"); - - LogManager.Info("[LayerManagementViewModel] 开始调用ExportToNwd API"); - - // 使用ExportToNwd API - document.ExportToNwd(saveFilePath, exportOptions); - - exportResult = true; - LogManager.Info("[LayerManagementViewModel] ExportToNwd API调用完成"); - - // 恢复所有隐藏项目的可见性 - try - { - if (document?.Models != null) - { - // 获取所有模型项并恢复可见性 - 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("[LayerManagementViewModel] 已恢复所有项目可见性"); - } - } - } - catch (Exception ex) - { - LogManager.Warning($"[LayerManagementViewModel] 恢复可见性失败: {ex.Message}"); - } + }); // 恢复原始选择 try @@ -2110,6 +2039,110 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + /// + /// 保存当前可见性状态 + /// + private Dictionary SaveCurrentVisibilityState(Document document) + { + var visibilityState = new Dictionary(); + + try + { + // 获取所有顶级项目并记录它们的可见性状态 + foreach (Model model in document.Models) + { + foreach (ModelItem topLevelItem in model.RootItem.Children) + { + try + { + // 记录是否隐藏(IsHidden为true表示隐藏,我们存储可见性所以取反) + visibilityState[topLevelItem] = !topLevelItem.IsHidden; + } + catch + { + // 如果无法获取状态,默认为可见 + visibilityState[topLevelItem] = true; + } + } + } + + LogManager.Info($"[LayerManagementViewModel] 保存可见性状态完成,记录了 {visibilityState.Count} 个顶级项目"); + } + catch (Exception ex) + { + LogManager.Error($"[LayerManagementViewModel] 保存可见性状态失败: {ex.Message}"); + } + + return visibilityState; + } + + /// + /// 恢复可见性状态 + /// + private void RestoreVisibilityState(Document document, Dictionary visibilityState) + { + try + { + LogManager.Info("[LayerManagementViewModel] 恢复可见性状态"); + + if (visibilityState == null || visibilityState.Count == 0) + { + LogManager.Warning("[LayerManagementViewModel] 没有可见性状态需要恢复,重置为全部可见"); + document.Models.ResetAllHidden(); + return; + } + + // 使用成熟的可见性控制模式 - 分别收集要显示和隐藏的项目 + 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 (Exception ex) + { + LogManager.Warning($"[LayerManagementViewModel] 处理项目可见性状态时出错: {ex.Message}"); + } + } + + // 首先重置所有项目为可见状态 + document.Models.ResetAllHidden(); + + // 然后隐藏原来应该隐藏的项目 + if (itemsToHide.Count > 0) + { + document.Models.SetHidden(itemsToHide, true); + LogManager.Info($"[LayerManagementViewModel] 恢复隐藏 {itemsToHide.Count} 个项目"); + } + + LogManager.Info("[LayerManagementViewModel] 可见性状态恢复完成"); + } + catch (Exception ex) + { + LogManager.Error($"[LayerManagementViewModel] 恢复可见性状态失败: {ex.Message}"); + // 失败时至少确保模型处于可见状态 + try + { + document.Models.ResetAllHidden(); + LogManager.Info("[LayerManagementViewModel] 已重置为全部可见状态"); + } + catch (Exception resetEx) + { + LogManager.Error($"[LayerManagementViewModel] 重置可见性也失败: {resetEx.Message}"); + } + } + } + ///