From 337ccbb43bb06c5428b4d48952b4bee336da96e8 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Tue, 2 Jun 2026 12:58:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20OnTreeViewSelected=20NRE=20+=20=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _isInternalSelection 为 true 时 OnTreeViewSelected 直接 return,阻断 NW→树→NW 循环 - 调试日志降为 Debug 级别 - doc.CurrentSelection 加空检查 --- src/UI/WPF/Views/AliasTreeControl.xaml.cs | 58 +++++++++++++---------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/UI/WPF/Views/AliasTreeControl.xaml.cs b/src/UI/WPF/Views/AliasTreeControl.xaml.cs index 468a27b..337f27d 100644 --- a/src/UI/WPF/Views/AliasTreeControl.xaml.cs +++ b/src/UI/WPF/Views/AliasTreeControl.xaml.cs @@ -196,7 +196,10 @@ namespace NavisworksTransport.UI.WPF.Views /// private void OnTreeViewSelected(AliasNodeViewModel node) { - LogManager.Info($"[别名树] OnTreeViewSelected 进入: {node.OriginalName}"); + // 由 NW 选择触发的 ExpandAndSelect 过程中的被动选中事件,不反向同步 + if (_isInternalSelection) return; + + LogManager.Debug($"[别名树] OnTreeViewSelected: {node.OriginalName}"); _isInternalSelection = true; try @@ -204,15 +207,17 @@ namespace NavisworksTransport.UI.WPF.Views _currentSelectionItem = node.ModelItem; TbCurrentNode.Text = $"当前: {node.OriginalName}"; var doc = NavisApplication.ActiveDocument; - if (doc != null && node.ModelItem != null) + if (doc != null && doc.CurrentSelection != null && node.ModelItem != null) { - LogManager.Info("[别名树] OnTreeViewSelected 设置NW选择"); var coll = new Autodesk.Navisworks.Api.ModelItemCollection { node.ModelItem }; try { doc.CurrentSelection.Clear(); doc.CurrentSelection.CopyFrom(coll); - LogManager.Info("[别名树] OnTreeViewSelected 设置完成"); + } + catch (NullReferenceException) + { + // NW API 内部 NRE(文档过渡状态),忽略 } catch (Exception ex) { @@ -222,13 +227,12 @@ namespace NavisworksTransport.UI.WPF.Views } catch (Exception ex) { - LogManager.Error($"[别名树] 选中同步异常: {ex.Message} {ex.StackTrace}"); + LogManager.Error($"[别名树] 选中同步异常: {ex.Message}"); } finally { _isInternalSelection = false; } - LogManager.Info("[别名树] OnTreeViewSelected 退出"); } private void StartInlineEdit(AliasNodeViewModel node, TreeViewItem tvi) @@ -255,14 +259,14 @@ namespace NavisworksTransport.UI.WPF.Views var doc = NavisApplication.ActiveDocument; if (doc == null) return; - var selected = doc.CurrentSelection.SelectedItems; + var selected = doc.CurrentSelection?.SelectedItems; if (selected.Count == 1) { var item = selected.First(); _currentSelectionItem = item; TbCurrentNode.Text = $"当前: {item.DisplayName}"; - LogManager.Info($"[别名树] NW选中: DisplayName={item.DisplayName}, ClassName={item.ClassName}"); + LogManager.Debug($"[别名树] NW选中: {item.DisplayName}"); ExpandAndSelect(item); } @@ -530,6 +534,20 @@ namespace NavisworksTransport.UI.WPF.Views LogManager.Info($"[别名树] ExpandAndSelect: target={item.DisplayName}"); + // 整个 ExpandAndSelect 期间阻止树→NW 反向联动 + _isInternalSelection = true; + try + { + ExpandAndSelectInternal(item); + } + finally + { + _isInternalSelection = false; + } + } + + private void ExpandAndSelectInternal(Autodesk.Navisworks.Api.ModelItem item) + { // 0. 清理上次按需加载的无别名深层节点 CleanupOnDemandNodes(); @@ -716,18 +734,15 @@ namespace NavisworksTransport.UI.WPF.Views { try { - LogManager.Info($"[别名树] EnsureAliased: key={kvp.Key}, alias={kvp.Value}"); + LogManager.Debug($"[别名树] EnsureAliased: key={kvp.Key}, alias={kvp.Value}"); var item = FindModelItemByNodeKey(kvp.Key); if (item == null) { - LogManager.Warning($"[别名树] EnsureAliased: FindModelItemByNodeKey 返回 null, key={kvp.Key}"); + LogManager.Debug($"[别名树] EnsureAliased: FindModelItemByNodeKey null, key={kvp.Key}"); continue; } - LogManager.Info($"[别名树] EnsureAliased: 找到 ModelItem DisplayName={item.DisplayName}, ClassName={item.ClassName}"); if (EnsurePathLoaded(item)) loaded++; - else - LogManager.Warning($"[别名树] EnsureAliased: EnsurePathLoaded 返回 false, item={item.DisplayName}"); } catch (Exception ex) { @@ -754,12 +769,12 @@ namespace NavisworksTransport.UI.WPF.Views } var chainStr = string.Join(" -> ", chain.ConvertAll(c => c.DisplayName ?? "?")); - LogManager.Info($"[别名树] EnsurePathLoaded: chain=[{chainStr}], depth={chain.Count - 1}"); + LogManager.Debug($"[别名树] EnsurePathLoaded: chain=[{chainStr}], depth={chain.Count - 1}"); // 2. 匹配根节点 var rootNodes = AliasTreeView.ItemsSource as System.Collections.ObjectModel.ObservableCollection; - if (rootNodes == null) { LogManager.Warning("[别名树] EnsurePathLoaded: rootNodes null"); return false; } + if (rootNodes == null) return false; AliasNodeViewModel treeNode = null; foreach (var rn in rootNodes) @@ -770,11 +785,7 @@ namespace NavisworksTransport.UI.WPF.Views break; } } - if (treeNode == null) - { - LogManager.Warning($"[别名树] EnsurePathLoaded: 根节点未匹配 chain[0]={chain[0].DisplayName}"); - return false; - } + if (treeNode == null) return false; if (chain.Count == 1) return true; // 3. 逐层加载 @@ -783,14 +794,10 @@ namespace NavisworksTransport.UI.WPF.Views for (int i = 1; i < chain.Count; i++) { var targetModelItem = chain[i]; - LogManager.Info($"[别名树] EnsurePathLoaded: L{i} cur={treeNode.OriginalName} target={targetModelItem.DisplayName} childCnt={treeNode.Children.Count}"); ExpandTreeNode(treeNode); if (treeNode.Children.Count == 1 && treeNode.Children[0].OriginalName == "加载中...") - { - LogManager.Info($"[别名树] EnsurePathLoaded: L{i} 懒加载子节点"); LazyLoadChildren(treeNode, aliasMap, displayAlias); - } AliasNodeViewModel child = null; foreach (var c in treeNode.Children) @@ -804,7 +811,6 @@ namespace NavisworksTransport.UI.WPF.Views if (child == null) { - LogManager.Info($"[别名树] EnsurePathLoaded: L{i} 未匹配, BuildNode 创建"); child = BuildNode(targetModelItem, aliasMap, displayAlias, treeNode.Depth + 1, treeNode.NodeKey, 0); if (child != null) @@ -816,7 +822,7 @@ namespace NavisworksTransport.UI.WPF.Views if (child == null) { - LogManager.Warning($"[别名树] EnsurePathLoaded: L{i} child 为 null, 中断"); + LogManager.Debug($"[别名树] EnsurePathLoaded: child null at L{i}"); return false; } treeNode = child;