diff --git a/src/Core/AliasTree/AliasNodeIdentity.cs b/src/Core/AliasTree/AliasNodeIdentity.cs index 299dec8..38ef7e1 100644 --- a/src/Core/AliasTree/AliasNodeIdentity.cs +++ b/src/Core/AliasTree/AliasNodeIdentity.cs @@ -49,9 +49,22 @@ namespace NavisworksTransport.Core.AliasTree if (item == null) throw new ArgumentNullException(nameof(item)); + // COM API 必须在 STA 主线程 + if (System.Threading.Thread.CurrentThread.GetApartmentState() != System.Threading.ApartmentState.STA) + LogManager.Error($"[别名树] FromModelItem 不在 STA 线程!"); + // 1. IndexPath — 复用 ModelItemAnalysisHelper - var indexPaths = ModelItemAnalysisHelper.GetModelItemIndexPaths(item); - string indexPath = indexPaths.FirstOrDefault() ?? string.Empty; + string indexPath; + try + { + var indexPaths = ModelItemAnalysisHelper.GetModelItemIndexPaths(item); + indexPath = indexPaths.FirstOrDefault() ?? string.Empty; + } + catch (Exception ex) + { + LogManager.Error($"[别名树] GetModelItemIndexPaths 异常: {ex.Message}"); + indexPath = string.Empty; + } // 2. DisplayPath — 父链 DisplayName + 同级索引 var parts = new List(); diff --git a/src/UI/WPF/Views/AliasTreeControl.xaml.cs b/src/UI/WPF/Views/AliasTreeControl.xaml.cs index b8ba86b..581cc55 100644 --- a/src/UI/WPF/Views/AliasTreeControl.xaml.cs +++ b/src/UI/WPF/Views/AliasTreeControl.xaml.cs @@ -172,6 +172,8 @@ namespace NavisworksTransport.UI.WPF.Views _isInternalSelection = true; try { + _currentSelectionItem = node.ModelItem; + TbCurrentNode.Text = $"当前: {node.OriginalName}"; var doc = NavisApplication.ActiveDocument; if (doc != null && node.ModelItem != null) { @@ -185,7 +187,7 @@ namespace NavisworksTransport.UI.WPF.Views } catch (Exception ex) { - LogManager.Error($"[别名树] NW选择异常: {ex.Message} {ex.StackTrace}"); + LogManager.Error($"[别名树] NW选择异常: {ex.GetType().Name}"); } } } @@ -217,37 +219,34 @@ namespace NavisworksTransport.UI.WPF.Views /// private void OnNavisSelectionChanged(object sender, EventArgs e) { - Dispatcher.BeginInvoke(new Action(() => + if (_isInternalSelection) return; + + try { - try + var doc = NavisApplication.ActiveDocument; + if (doc == null) return; + + var selected = doc.CurrentSelection.SelectedItems; + if (selected.Count == 1) { - var doc = NavisApplication.ActiveDocument; - if (doc == null) return; + var item = selected.First(); + _currentSelectionItem = item; + TbCurrentNode.Text = $"当前: {item.DisplayName}"; - 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.Info($"[别名树] NW选中: DisplayName={item.DisplayName}, ClassName={item.ClassName}"); - - // 内部触发时不展开(别名树点击引起的),只更新 _currentSelectionItem - if (!_isInternalSelection) - ExpandAndSelect(item); - } - else - { - _currentSelectionItem = null; - TbCurrentNode.Text = selected.Count > 1 ? $"当前: ({selected.Count} 个选中)" : "当前: 无"; - } + ExpandAndSelect(item); } - catch (Exception ex) + else { - LogManager.Error($"[别名树] 选择变化处理失败: {ex.Message}"); + _currentSelectionItem = null; + TbCurrentNode.Text = selected.Count > 1 ? $"当前: ({selected.Count} 个选中)" : "当前: 无"; } - })); + } + catch (Exception ex) + { + LogManager.Error($"[别名树] 选择变化处理异常: {ex.Message}"); + } } // ============================================================ @@ -306,7 +305,16 @@ namespace NavisworksTransport.UI.WPF.Views { if (modelItem == null) return null; - var identity = AliasNodeIdentity.FromModelItem(modelItem); + AliasNodeIdentity identity; + try + { + identity = AliasNodeIdentity.FromModelItem(modelItem); + } + catch (Exception ex) + { + LogManager.Error($"[别名树] BuildNode FromModelItem 异常: {ex.Message}"); + return null; + } string key = identity.ToKey(); string alias = null; @@ -347,6 +355,34 @@ namespace NavisworksTransport.UI.WPF.Views return node; } + /// + /// 只加载指定索引的子节点(不全量加载,用于 ExpandAndSelect 加速) + /// + private void EnsureChildLoaded(AliasNodeViewModel parent, int index) + { + if (parent.Children.Count != 1 || parent.Children[0].OriginalName != "加载中...") + return; + + parent.Children.Clear(); + try + { + var doc = NavisApplication.ActiveDocument; + if (doc == null) return; + var item = FindModelItemByNodeKey(parent.NodeKey); + if (item == null) return; + + var aliasMap = _dataStore?.LoadAll(); + var childrenList = item.Children.ToList(); + int loadCount = Math.Min(index + 1, childrenList.Count); + for (int i = 0; i < loadCount; i++) + { + var childNode = BuildNode(childrenList[i], aliasMap, parent.Depth + 1); + if (childNode != null) { childNode.Parent = parent; parent.Children.Add(childNode); } + } + } + catch (Exception ex) { LogManager.Error($"[别名树] EnsureChildLoaded: {ex.Message}"); } + } + /// /// 懒加载子节点(在 Expanded 事件中触发) /// @@ -579,7 +615,7 @@ namespace NavisworksTransport.UI.WPF.Views return; } - // 沿 IndexPath 逐层展开 — 纯 ViewModel 导航,不依赖 TreeViewItem + // 沿 IndexPath 逐层展开 — 只加载路径上的子节点 AliasNodeViewModel current = rootNode; for (int i = startPart; i < parts.Length; i++) @@ -588,11 +624,13 @@ namespace NavisworksTransport.UI.WPF.Views int adjIdx = childIdx - 1; if (adjIdx < 0) adjIdx = 0; - // 尝试获取当前节点 TreeViewItem 用于展开(没有就算了,继续) + // 展开当前节点 var tvi = GetTreeViewItemForNode(current); if (tvi != null) { + _isProgrammaticExpand = true; tvi.IsExpanded = true; + _isProgrammaticExpand = false; tvi.UpdateLayout(); } var aliasMap = _dataStore?.LoadAll(); @@ -604,8 +642,7 @@ namespace NavisworksTransport.UI.WPF.Views return; } - var child = current.Children[adjIdx]; - current = child; + current = current.Children[adjIdx]; } // 到达目标:强制父节点 BringIntoView,延迟后获取容器选中 @@ -1081,14 +1118,15 @@ namespace NavisworksTransport.UI.WPF.Views private void OnTreeViewItemExpanded(object sender, RoutedEventArgs e) { + if (_isProgrammaticExpand) return; if (!(e.OriginalSource is TreeViewItem tvi) || !(tvi.DataContext is AliasNodeViewModel node)) return; - var aliasMap = _dataStore?.LoadAll(); LazyLoadChildren(node, aliasMap); } private bool _isProgrammaticSelect; + private bool _isProgrammaticExpand; /// /// 树节点被选中时:如果 500ms 内再次选中同一节点 → 进入内联编辑 @@ -1098,21 +1136,32 @@ namespace NavisworksTransport.UI.WPF.Views /// private void OnTreeViewItemRightClick(object sender, MouseButtonEventArgs e) { - var tvi = FindAncestor(e.OriginalSource as DependencyObject); - if (tvi != null) + try { - tvi.IsSelected = true; - tvi.Focus(); + var tvi = FindAncestor(e.OriginalSource as DependencyObject); + if (tvi != null) + { + tvi.IsSelected = true; + tvi.Focus(); + } + } + catch (Exception ex) + { + LogManager.Error($"[别名树] RCK-异常: {ex.GetType().Name}"); } } private static TreeViewItem FindAncestor(DependencyObject current) { - while (current != null) + try { - if (current is TreeViewItem tvi) return tvi; - current = VisualTreeHelper.GetParent(current); + while (current != null) + { + if (current is TreeViewItem tvi) return tvi; + current = VisualTreeHelper.GetParent(current); + } } + catch { } return null; } @@ -1121,10 +1170,19 @@ namespace NavisworksTransport.UI.WPF.Views /// private void OnTreeViewItemLeftClick(object sender, MouseButtonEventArgs e) { - var tvi = FindAncestor(e.OriginalSource as DependencyObject); - if (tvi != null && tvi.IsSelected && tvi.DataContext is AliasNodeViewModel node && !node.IsOrphan) + try { - StartInlineEdit(node); + // 从点击元素的 DataContext 获取节点,不遍历可视化树 + if (e.OriginalSource is FrameworkElement fe && fe.DataContext is AliasNodeViewModel node && !node.IsOrphan) + { + var selNode = GetSelectedNode(); + if (node == selNode) + StartInlineEdit(node); + } + } + catch (Exception ex) + { + LogManager.Error($"[别名树] LCK-异常: {ex.GetType().Name}"); } }