From c002feee51e6707fde7b5d727cca2c8da29b4e26 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sun, 31 May 2026 13:17:52 +0800 Subject: [PATCH] fix: ExpandAndSelect uses ModelItem.Equals for precise sibling matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 AliasNodeViewModel.ModelItem 属性(持有 Navisworks 原生引用) - BuildNode 中存储 ModelItem - ExpandAndSelect 重写为 DFS 递归,用 ModelItem.Equals 精确匹配 (同 ModelItemAnalysisHelper.ModelItemEquals 逻辑,底层原生对象比较) - 不再依赖 IndexPath 或 _nodeMap 做选中同步 --- src/UI/WPF/ViewModels/AliasNodeViewModel.cs | 6 +- src/UI/WPF/Views/AliasTreeControl.xaml.cs | 80 +++++++++++++-------- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/UI/WPF/ViewModels/AliasNodeViewModel.cs b/src/UI/WPF/ViewModels/AliasNodeViewModel.cs index fd02a01..e4d5a48 100644 --- a/src/UI/WPF/ViewModels/AliasNodeViewModel.cs +++ b/src/UI/WPF/ViewModels/AliasNodeViewModel.cs @@ -1,5 +1,6 @@ using System; using System.ComponentModel; +using Autodesk.Navisworks.Api; namespace NavisworksTransport.UI.WPF.ViewModels { @@ -17,9 +18,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels private bool _hasAlias; private int _childCount; - /// 节点的序列化标识 key(对应 AliasNodeIdentity.ToKey()) + /// 节点的序列化标识 key public string NodeKey { get; set; } + /// Navisworks ModelItem 引用(用于选中同步的比较) + public Autodesk.Navisworks.Api.ModelItem ModelItem { get; set; } + /// 当前显示文本(别名优先,无别名回退到原名) public string DisplayName { diff --git a/src/UI/WPF/Views/AliasTreeControl.xaml.cs b/src/UI/WPF/Views/AliasTreeControl.xaml.cs index 4e2aaaa..e126192 100644 --- a/src/UI/WPF/Views/AliasTreeControl.xaml.cs +++ b/src/UI/WPF/Views/AliasTreeControl.xaml.cs @@ -41,10 +41,13 @@ namespace NavisworksTransport.UI.WPF.Views AliasTreeView.ItemsSource = rootNodes; // 文档切换事件 - NavisApplication.ActiveDocumentChanged += (s, e) => RebuildTree(); + NavisApplication.ActiveDocumentChanged += (s, e) => { _built = false; RebuildTree(); }; NavisApplication.ActiveDocumentChanging += (s, e) => { _built = false; }; HookSelectionEvents(); + + // 立即构建:面板打开时如果文档已存在,不走事件也要构建 + RebuildTree(); } /// @@ -246,6 +249,7 @@ namespace NavisworksTransport.UI.WPF.Views var node = new AliasNodeViewModel { NodeKey = key, + ModelItem = modelItem, OriginalName = modelItem.DisplayName ?? "?", Alias = alias, ChildCount = modelItem.Children.Count() @@ -427,51 +431,67 @@ namespace NavisworksTransport.UI.WPF.Views // ============================================================ // 展开并高亮指定 ModelItem + // 策略:DFS 遍历别名树,用 ModelItem.Equals 精确匹配。 + // 遇到未展开节点时先触发 LazyLoadChildren,然后递归搜索。 // ============================================================ private void ExpandAndSelect(Autodesk.Navisworks.Api.ModelItem item) { - var identity = AliasNodeIdentity.FromModelItem(item); - string key = identity.ToKey(); + var rootNodes = AliasTreeView.ItemsSource + as System.Collections.ObjectModel.ObservableCollection; + if (rootNodes == null || rootNodes.Count == 0) return; - if (!_nodeMap.TryGetValue(key, out var targetNode)) - return; - - // 收集从根到目标的路径 - var path = new List(); - var current = targetNode; - while (current != null) + foreach (var rootNode in rootNodes) { - path.Insert(0, current); - current = current.Parent; + if (ExpandAndSelectRecursive(rootNode, item, AliasTreeView)) + return; } + } - // 逐层展开 - ItemsControl currentContainer = AliasTreeView; - foreach (var node in path) + private bool ExpandAndSelectRecursive( + AliasNodeViewModel node, + Autodesk.Navisworks.Api.ModelItem target, + ItemsControl currentContainer) + { + // 1. 展开容器 + 触发懒加载 + if (currentContainer is TreeViewItem tvi) { - // 触发懒加载 - var aliasMap = _dataStore?.LoadAll(); - LazyLoadChildren(node, aliasMap); + tvi.IsExpanded = true; + tvi.UpdateLayout(); + } + var aliasMap = _dataStore?.LoadAll(); + LazyLoadChildren(node, aliasMap); - if (currentContainer is TreeViewItem tvi) + // 2. 检查自身(ModelItem.Equals 是底层原生对象比较,精确区分同名兄弟) + if (node.ModelItem != null && node.ModelItem.Equals(target)) + { + if (currentContainer is TreeViewItem selfTvi) { - tvi.IsExpanded = true; - tvi.UpdateLayout(); + selfTvi.IsSelected = true; + selfTvi.BringIntoView(); } - - var container = currentContainer.ItemContainerGenerator.ContainerFromItem(node) as TreeViewItem; - if (container == null) break; - currentContainer = container; + return true; } - // 高亮目标 - if (currentContainer is TreeViewItem targetTvi && targetTvi.DataContext is AliasNodeViewModel target - && target.NodeKey == key) + // 3. DFS 子节点 + for (int i = 0; i < node.Children.Count; i++) { - targetTvi.IsSelected = true; - targetTvi.BringIntoView(); + var child = node.Children[i]; + var childContainer = currentContainer.ItemContainerGenerator + .ContainerFromItem(child) as TreeViewItem; + if (childContainer == null) + { + currentContainer.UpdateLayout(); + childContainer = currentContainer.ItemContainerGenerator + .ContainerFromItem(child) as TreeViewItem; + } + if (childContainer == null) continue; + + if (ExpandAndSelectRecursive(child, target, childContainer)) + return true; } + + return false; } // ============================================================