feat: alias persistence via PathDatabase SQLite

- AliasTreePlugin 监听文档生命周期,连接 PathDatabase
- AliasDataStore 写入 PathDatabase.SQLiteConnection
- 编辑别名实时持久化,重启后自动恢复
- 修复 _isInternalSelection 阻塞 _currentSelectionItem 更新导致编辑写错节点
This commit is contained in:
tian 2026-05-31 14:59:54 +08:00
parent 9a6859cdb5
commit ad398652a7
2 changed files with 83 additions and 20 deletions

View File

@ -2,36 +2,30 @@ using Autodesk.Navisworks.Api.Plugins;
using NavisworksTransport.UI.WPF.Views;
using NavisworksTransport.Utils;
using System.Windows.Forms.Integration;
using NavisApplication = Autodesk.Navisworks.Api.Application;
namespace NavisworksTransport.Core.AliasTree
{
/// <summary>
/// 别名导航树 — DockPanePlugin 入口
///
/// 使用方式:
/// 1. 启动 Navisworks
/// 2. View → Docking Windows → 别名导航树
/// 3. 手动拖放到内置 Selection Tree 下方
/// </summary>
[Plugin("NavisworksTransport.AliasTree", "Tian",
DisplayName = "别名导航树",
ToolTip = "自定义节点别名管理面板 — 双击编辑、右键菜单、JSON 导入导出")]
[DockPanePlugin(300, 400, FixedSize = false, AutoScroll = true)]
public class AliasTreePlugin : DockPanePlugin
{
private AliasTreeControl _control;
public override System.Windows.Forms.Control CreateControlPane()
{
LogManager.Info("[别名树] 创建 DockPane 面板");
var eh = new ElementHost
{
AutoSize = true
};
var control = new AliasTreeControl();
eh.Child = control;
var eh = new ElementHost { AutoSize = true };
_control = new AliasTreeControl();
eh.Child = _control;
eh.CreateControl();
// 面板创建时如果文档已存在,立即连接数据库
TryConnectToDatabase();
return eh;
}
@ -45,7 +39,57 @@ namespace NavisworksTransport.Core.AliasTree
eh.Child = null;
}
_control = null;
pane?.Dispose();
}
protected override void OnLoaded()
{
base.OnLoaded();
NavisApplication.ActiveDocumentChanged += OnDocumentChanged;
}
protected override void OnUnloading()
{
NavisApplication.ActiveDocumentChanged -= OnDocumentChanged;
base.OnUnloading();
}
private void OnDocumentChanged(object sender, System.EventArgs e)
{
TryConnectToDatabase();
}
private void TryConnectToDatabase()
{
if (_control == null) return;
try
{
var doc = NavisApplication.ActiveDocument;
if (doc == null || string.IsNullOrEmpty(doc.FileName))
{
_control.SetDataStore(null);
return;
}
var pathManager = PathPlanningManager.GetActivePathManager();
var db = pathManager?.GetPathDatabase();
if (db?.Connection == null)
{
LogManager.Warning("[别名树] PathDatabase 未就绪,等待文档加载完成");
return;
}
var store = new AliasDataStore(db.Connection);
store.EnsureTableExists();
_control.SetDataStore(store);
LogManager.Info("[别名树] 已连接别名数据库");
}
catch (System.Exception ex)
{
LogManager.Error($"[别名树] 连接数据库失败: {ex.Message}");
}
}
}
}

View File

@ -56,7 +56,25 @@ namespace NavisworksTransport.UI.WPF.Views
public void SetDataStore(AliasDataStore store)
{
_dataStore = store;
RebuildTree();
if (!_built)
RebuildTree();
else
RefreshAliasesFromStore();
}
/// <summary>
/// 从 AliasDataStore 刷新所有节点的别名显示(不重建树)
/// </summary>
private void RefreshAliasesFromStore()
{
if (_dataStore == null) return;
var aliasMap = _dataStore.LoadAll();
foreach (var kvp in aliasMap)
{
if (_nodeMap.TryGetValue(kvp.Key, out var node))
node.Alias = kvp.Value;
}
}
/// <summary>
@ -141,8 +159,6 @@ namespace NavisworksTransport.UI.WPF.Views
/// </summary>
private void OnNavisSelectionChanged(object sender, EventArgs e)
{
if (_isInternalSelection) return;
Dispatcher.BeginInvoke(new Action(() =>
{
try
@ -160,8 +176,9 @@ namespace NavisworksTransport.UI.WPF.Views
LogManager.Info($"[别名树] NW选中: DisplayName={item.DisplayName}, ClassName={item.ClassName}");
// 在树中展开并高亮
ExpandAndSelect(item);
// 内部触发时不展开(别名树点击引起的),只更新 _currentSelectionItem
if (!_isInternalSelection)
ExpandAndSelect(item);
}
else
{
@ -603,6 +620,7 @@ namespace NavisworksTransport.UI.WPF.Views
if (string.IsNullOrEmpty(input)) return;
var identity = AliasNodeIdentity.FromModelItem(_currentSelectionItem);
LogManager.Info($"[别名树] 保存别名: {input}, NodeKey={identity.ToKey()}");
_dataStore.SetAlias(identity, input);
TxtAliasInput.Clear();
@ -707,6 +725,7 @@ namespace NavisworksTransport.UI.WPF.Views
if (textBox?.DataContext is AliasNodeViewModel node)
{
string newAlias = textBox.Text?.Trim();
LogManager.Info($"[别名树] 内联编辑: {newAlias}, NodeKey={node.NodeKey}");
if (_dataStore != null)
{
AliasNodeIdentity.TryParseKey(node.NodeKey, out var identity);