fix: OnTreeViewSelected NRE + 日志清理

- _isInternalSelection 为 true 时 OnTreeViewSelected 直接 return,阻断 NW→树→NW 循环
- 调试日志降为 Debug 级别
- doc.CurrentSelection 加空检查
This commit is contained in:
tian 2026-06-02 12:58:38 +08:00
parent 8a8153dba0
commit 337ccbb43b

View File

@ -196,7 +196,10 @@ namespace NavisworksTransport.UI.WPF.Views
/// </summary>
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<AliasNodeViewModel>;
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;