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;
}
// ============================================================