fix: ExpandAndSelect uses ModelItem.Equals for precise sibling matching
- 新增 AliasNodeViewModel.ModelItem 属性(持有 Navisworks 原生引用) - BuildNode 中存储 ModelItem - ExpandAndSelect 重写为 DFS 递归,用 ModelItem.Equals 精确匹配 (同 ModelItemAnalysisHelper.ModelItemEquals 逻辑,底层原生对象比较) - 不再依赖 IndexPath 或 _nodeMap 做选中同步
This commit is contained in:
parent
4feb12f6b9
commit
c002feee51
@ -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;
|
||||
|
||||
/// <summary>节点的序列化标识 key(对应 AliasNodeIdentity.ToKey())</summary>
|
||||
/// <summary>节点的序列化标识 key</summary>
|
||||
public string NodeKey { get; set; }
|
||||
|
||||
/// <summary>Navisworks ModelItem 引用(用于选中同步的比较)</summary>
|
||||
public Autodesk.Navisworks.Api.ModelItem ModelItem { get; set; }
|
||||
|
||||
/// <summary>当前显示文本(别名优先,无别名回退到原名)</summary>
|
||||
public string DisplayName
|
||||
{
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -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<AliasNodeViewModel>;
|
||||
if (rootNodes == null || rootNodes.Count == 0) return;
|
||||
|
||||
if (!_nodeMap.TryGetValue(key, out var targetNode))
|
||||
return;
|
||||
|
||||
// 收集从根到目标的路径
|
||||
var path = new List<AliasNodeViewModel>();
|
||||
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;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
|
||||
Loading…
Reference in New Issue
Block a user