NavisworksTransport/MainPlugin.cs
2025-06-21 17:38:48 +08:00

3214 lines
128 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NavisApplication = Autodesk.Navisworks.Api.Application;
namespace NavisworksTransport
{
/// <summary>
/// 全局异常处理工具类
/// </summary>
public static class GlobalExceptionHandler
{
private static bool _isInitialized = false;
/// <summary>
/// 初始化全局异常处理器
/// </summary>
public static void Initialize()
{
if (_isInitialized) return;
try
{
// 捕获未处理的异常
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
System.Windows.Forms.Application.ThreadException += OnThreadException;
_isInitialized = true;
LogManager.Info("[全局异常] 全局异常处理器已初始化");
}
catch (Exception ex)
{
LogManager.Error($"[全局异常] 初始化异常处理器失败: {ex.Message}");
}
}
/// <summary>
/// 处理未捕获的异常
/// </summary>
private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
try
{
Exception ex = e.ExceptionObject as Exception;
string message = ex?.Message ?? "未知异常";
string stackTrace = ex?.StackTrace ?? "无堆栈信息";
LogManager.Error($"[全局异常] 未处理异常: {message}");
LogManager.Error($"[全局异常] 堆栈信息: {stackTrace}");
LogManager.Error($"[全局异常] 异常类型: {ex?.GetType().Name ?? "Unknown"}");
LogManager.Error($"[全局异常] 是否终止: {e.IsTerminating}");
// 显示用户友好的错误信息
ShowErrorDialog("程序发生未预期的错误", message, ex);
// 尝试恢复关键组件
TryRecoverComponents();
}
catch
{
// 异常处理中的异常,保持静默
}
}
/// <summary>
/// 处理线程异常
/// </summary>
private static void OnThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
try
{
Exception ex = e.Exception;
LogManager.Error($"[全局异常] 线程异常: {ex.Message}");
LogManager.Error($"[全局异常] 堆栈信息: {ex.StackTrace}");
LogManager.Error($"[全局异常] 异常类型: {ex.GetType().Name}");
// 显示用户友好的错误信息
ShowErrorDialog("程序发生线程错误", ex.Message, ex);
// 尝试恢复关键组件
TryRecoverComponents();
}
catch
{
// 异常处理中的异常,保持静默
}
}
/// <summary>
/// 安全执行方法,捕获所有异常
/// </summary>
public static T SafeExecute<T>(Func<T> action, T defaultValue = default(T), string operationName = "操作")
{
try
{
return action();
}
catch (Exception ex)
{
LogManager.Error($"[安全执行] {operationName}失败: {ex.Message}");
LogManager.Error($"[安全执行] 堆栈信息: {ex.StackTrace}");
LogManager.Error($"[安全执行] 异常类型: {ex.GetType().Name}");
// 对于用户操作,显示简短的错误提示
if (!string.IsNullOrEmpty(operationName) && operationName != "操作")
{
ShowErrorToast($"{operationName}失败: {ex.Message}");
}
return defaultValue;
}
}
/// <summary>
/// 安全执行方法(无返回值)
/// </summary>
public static void SafeExecute(Action action, string operationName = "操作")
{
SafeExecute(() => { action(); return true; }, false, operationName);
}
/// <summary>
/// 显示错误对话框
/// </summary>
private static void ShowErrorDialog(string title, string message, Exception ex = null)
{
try
{
string detailMessage = message;
if (ex != null)
{
detailMessage += $"\n\n技术详情: {ex.GetType().Name}";
if (!string.IsNullOrEmpty(ex.Message))
{
detailMessage += $"\n错误信息: {ex.Message}";
}
}
MessageBox.Show(detailMessage, title, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
catch
{
// 如果连错误对话框都显示不了,就保持静默
}
}
/// <summary>
/// 显示简短的错误提示
/// </summary>
private static void ShowErrorToast(string message)
{
try
{
MessageBox.Show(message, "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
catch
{
// 保持静默
}
}
/// <summary>
/// 尝试恢复关键组件
/// </summary>
private static void TryRecoverComponents()
{
try
{
LogManager.Info("[全局异常] 尝试恢复关键组件...");
// 尝试重置路径编辑状态
var activeManager = PathPlanningManager.GetActivePathManager();
if (activeManager != null)
{
activeManager.ResetPathEditState();
LogManager.Info("[全局异常] 已重置路径编辑状态");
}
// 尝试清除临时高亮
if (NavisApplication.ActiveDocument?.Models != null)
{
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
LogManager.Info("[全局异常] 已清除临时材质");
}
LogManager.Info("[全局异常] 组件恢复完成");
}
catch (Exception ex)
{
LogManager.Error($"[全局异常] 组件恢复失败: {ex.Message}");
}
}
}
[PluginAttribute("Basic", "Tian", ToolTip = "Transport Plugin", DisplayName = "Transport Plugin")]
[AddInPlugin(AddInLocation.AddIn)] // 将插件显示在Navisworks的"附加模块"选项卡中
public class Main : AddInPlugin
{
/// <summary>
/// 会话初始化标志用于确保在同一Navisworks会话中只清空一次日志
/// </summary>
private static bool _isSessionInitialized = false;
// 静态变量保存控制面板实例,避免重复创建
private static Form _controlPanelForm = null;
// 保存关键UI控件引用用于实时更新
private static Label _instructionLabel = null;
private static Label _selectedModelsLabel = null;
private static ListView _logisticsListView = null;
private static Label _statsLabel = null;
// 动画管理器实例(类级别变量)
private static PathAnimationManager _animationManager;
// 路径规划管理器实例
private static PathPlanningManager _pathPlanningManager;
// 路径编辑UI控件引用
private static ListView _pathListView = null;
private static Label _currentPathStatusLabel = null;
private static ListView _currentPathPointsListView = null; // 使用ListView替代ListBox
public override int Execute(params string[] parameters)
{
return GlobalExceptionHandler.SafeExecute(() =>
{
// 初始化会话(只执行一次)
if (!_isSessionInitialized)
{
InitializeSession();
_isSessionInitialized = true;
}
// 显示控制面板
ShowDockPane();
return 0;
}, -1, "插件初始化");
}
/// <summary>
/// 显示左侧控制面板(无模态对话框)
/// </summary>
private void ShowDockPane()
{
GlobalExceptionHandler.SafeExecute(() =>
{
// 如果面板已存在,直接显示并置前
if (_controlPanelForm != null && !_controlPanelForm.IsDisposed)
{
_controlPanelForm.Show();
_controlPanelForm.BringToFront();
_controlPanelForm.Focus();
LogManager.Info("控制面板已显示并置前");
return;
}
// 创建新的控制面板
ShowCategorySelectionDialog();
}, "显示控制面板");
}
/// <summary>
/// 初始化插件会话
/// </summary>
private void InitializeSession()
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info("=== 物流路径规划插件初始化开始 ===");
// 初始化全局异常处理
GlobalExceptionHandler.Initialize();
// 初始化路径规划管理器
InitializePathPlanningManager();
LogManager.Info("插件会话初始化完成");
}, "初始化会话");
}
/// <summary>
/// 初始化路径规划管理器并设置事件订阅
/// </summary>
private void InitializePathPlanningManager()
{
try
{
LogManager.Info("开始初始化PathPlanningManager");
// 创建或获取PathPlanningManager实例
_pathPlanningManager = PathPlanningManager.GetActivePathManager() ?? new PathPlanningManager();
// 订阅路径编辑状态变更事件
_pathPlanningManager.PathEditStateChanged += OnPathEditStateChanged;
// 订阅路径点相关事件
_pathPlanningManager.PathPointAddedIn3D += OnPathPointAddedIn3D;
_pathPlanningManager.PathPointRemovedFrom3D += OnPathPointRemovedFrom3D;
_pathPlanningManager.PathPointsListUpdated += OnPathPointsListUpdated;
// 订阅路径变更事件
_pathPlanningManager.CurrentRouteChanged += OnCurrentRouteChanged;
// 订阅状态和错误事件
_pathPlanningManager.StatusChanged += OnPathManagerStatusChanged;
_pathPlanningManager.ErrorOccurred += OnPathManagerErrorOccurred;
LogManager.Info("PathPlanningManager初始化完成事件订阅成功");
}
catch (Exception ex)
{
LogManager.Error($"初始化PathPlanningManager失败: {ex.Message}");
}
}
/// <summary>
/// 显示类别选择和主控制面板(无模态对话框)
/// </summary>
private void ShowCategorySelectionDialog()
{
GlobalExceptionHandler.SafeExecute(() =>
{
// 创建主窗体
_controlPanelForm = new Form
{
Text = "物流路径规划控制面板",
Size = new Size(380, 700),
StartPosition = FormStartPosition.Manual,
Location = new Point(20, 140), // 避免遮挡菜单
TopMost = true,
ShowInTaskbar = false,
MaximizeBox = false,
MinimizeBox = false,
FormBorderStyle = FormBorderStyle.FixedSingle
};
// 添加选择变化事件监听
NavisApplication.ActiveDocument.CurrentSelection.Changed += OnSelectionChanged;
// 创建主面板
Panel mainPanel = new Panel
{
Dock = DockStyle.Fill,
Padding = new Padding(5)
};
_controlPanelForm.Controls.Add(mainPanel);
// 创建Tab控件
TabControl tabControl = new TabControl
{
Dock = DockStyle.Fill,
Font = new Font("微软雅黑", 8)
};
mainPanel.Controls.Add(tabControl);
// 创建四个Tab页
CreateModelSettingsTab(tabControl);
CreatePathEditingTab(tabControl);
CreateAnimationControlTab(tabControl);
CreateSystemManagementTab(tabControl);
// 创建底部操作栏
Panel bottomPanel = new Panel
{
Height = 50,
Dock = DockStyle.Bottom
};
mainPanel.Controls.Add(bottomPanel);
// 帮助按钮
Button helpButton = new Button
{
Text = "帮助",
Size = new Size(60, 30),
Location = new Point(10, 10),
Font = new Font("微软雅黑", 8)
};
bottomPanel.Controls.Add(helpButton);
// 关于按钮
Button aboutButton = new Button
{
Text = "关于",
Size = new Size(60, 30),
Location = new Point(80, 10),
Font = new Font("微软雅黑", 8)
};
bottomPanel.Controls.Add(aboutButton);
// 关闭按钮
Button closeButton = new Button
{
Text = "关闭",
Size = new Size(60, 30),
Location = new Point(290, 10),
Font = new Font("微软雅黑", 8)
};
bottomPanel.Controls.Add(closeButton);
// 关闭按钮事件处理
closeButton.Click += (sender, e) =>
{
_controlPanelForm.Close();
};
// 事件处理
helpButton.Click += (sender, e) =>
{
MessageBox.Show("物流路径规划插件使用说明:\n\n1. 类别设置:设置对象类别和可见性\n2. 路径编辑创建和管理3D路径\n3. 动画控制:创建路径动画\n4. 系统管理:插件设置和日志",
"帮助", MessageBoxButtons.OK, MessageBoxIcon.Information);
};
aboutButton.Click += (sender, e) =>
{
MessageBox.Show("物流路径规划插件 v1.0\n\n适用于 Navisworks 2017\n开发AI助手\n\n功能3D路径规划、动画创建、碰撞检测",
"关于插件", MessageBoxButtons.OK, MessageBoxIcon.Information);
};
// 添加窗口关闭事件处理
_controlPanelForm.FormClosed += (sender, e) =>
{
// 清理选择事件监听
try
{
NavisApplication.ActiveDocument.CurrentSelection.Changed -= OnSelectionChanged;
}
catch (Exception ex)
{
LogManager.Error($"清理选择事件监听失败: {ex.Message}");
}
_controlPanelForm = null; // 清空引用
_instructionLabel = null;
_selectedModelsLabel = null;
_logisticsListView = null;
_statsLabel = null;
LogManager.Info("控制面板已关闭,已清理所有引用和事件监听");
};
// 显示无模态对话框
_controlPanelForm.Show();
LogManager.Info("控制面板已显示在屏幕左侧");
}, "显示主控制面板");
}
/// <summary>
/// 创建类别设置Tab页
/// </summary>
private void CreateModelSettingsTab(TabControl tabControl)
{
TabPage modelTab = new TabPage("类别设置");
modelTab.Padding = new Padding(10);
Panel scrollPanel = new Panel
{
Dock = DockStyle.Fill,
AutoScroll = true
};
modelTab.Controls.Add(scrollPanel);
int currentY = 10;
// 选择提示和状态信息(保存引用)
_instructionLabel = new Label
{
Text = "请在主界面中点击选择模型",
Font = new Font("微软雅黑", 8, FontStyle.Bold),
ForeColor = System.Drawing.Color.Orange,
AutoSize = true,
Location = new Point(10, currentY)
};
scrollPanel.Controls.Add(_instructionLabel);
currentY += 25;
// 显示选中模型名称(保存引用)
_selectedModelsLabel = new Label
{
Text = "选中模型: ",
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.DarkBlue,
AutoSize = true,
Location = new Point(10, currentY),
MaximumSize = new Size(320, 0),
Visible = false // 初始隐藏
};
scrollPanel.Controls.Add(_selectedModelsLabel);
currentY += 30;
// 类别属性设置
GroupBox categoryGroupBox = new GroupBox
{
Text = "类别属性设置",
Location = new Point(10, currentY),
Size = new Size(340, 80),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(categoryGroupBox);
CreateCategoryDropdown(categoryGroupBox);
currentY += 100;
// 物流模型列表
GroupBox logisticsListGroupBox = new GroupBox
{
Text = "物流模型列表",
Location = new Point(10, currentY),
Size = new Size(340, 180),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(logisticsListGroupBox);
CreateLogisticsModelList(logisticsListGroupBox);
currentY += 190;
// 统计信息(简化为一行,保存引用)
_statsLabel = new Label
{
Text = "统计: 正在计算物流模型信息...",
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.DarkGreen,
AutoSize = true,
Location = new Point(10, currentY)
};
scrollPanel.Controls.Add(_statsLabel);
UpdateLogisticsStatsStatic(_statsLabel);
currentY += 25;
// 可见性控制
GroupBox visibilityGroupBox = new GroupBox
{
Text = "可见性控制",
Location = new Point(10, currentY),
Size = new Size(340, 100),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(visibilityGroupBox);
CreateVisibilityControls(visibilityGroupBox);
tabControl.TabPages.Add(modelTab);
// 初始更新选择显示
UpdateSelectionDisplay();
}
/// <summary>
/// 创建路径编辑Tab页
/// </summary>
private void CreatePathEditingTab(TabControl tabControl)
{
TabPage pathTab = new TabPage("路径编辑");
pathTab.Padding = new Padding(10);
Panel scrollPanel = new Panel
{
Dock = DockStyle.Fill,
AutoScroll = true
};
pathTab.Controls.Add(scrollPanel);
int currentY = 10;
// 第一层:路径列表管理
GroupBox pathListGroupBox = new GroupBox
{
Text = "路径列表管理",
Location = new Point(10, currentY),
Size = new Size(320, 160),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(pathListGroupBox);
CreatePathListManagement(pathListGroupBox);
currentY += 180;
// 第二层:当前路径编辑
GroupBox currentPathGroupBox = new GroupBox
{
Text = "当前路径编辑",
Location = new Point(10, currentY),
Size = new Size(320, 250),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(currentPathGroupBox);
CreateCurrentPathEditor(currentPathGroupBox);
currentY += 270;
// 第三层:文件管理
GroupBox fileManagementGroupBox = new GroupBox
{
Text = "路径文件管理",
Location = new Point(10, currentY),
Size = new Size(320, 80),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(fileManagementGroupBox);
CreatePathFileManagement(fileManagementGroupBox);
tabControl.TabPages.Add(pathTab);
}
/// <summary>
/// 创建动画控制Tab页
/// </summary>
private void CreateAnimationControlTab(TabControl tabControl)
{
TabPage animationTab = new TabPage("动画控制");
animationTab.Padding = new Padding(10);
Panel scrollPanel = new Panel
{
Dock = DockStyle.Fill,
AutoScroll = true
};
animationTab.Controls.Add(scrollPanel);
int currentY = 10;
// 动画参数设置
GroupBox animationGroupBox = new GroupBox
{
Text = "动画参数设置",
Location = new Point(10, currentY),
Size = new Size(320, 190),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(animationGroupBox);
CreateAnimationControls(animationGroupBox);
currentY += 210;
// 播放控制
GroupBox playbackGroupBox = new GroupBox
{
Text = "播放控制",
Location = new Point(10, currentY),
Size = new Size(320, 100),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(playbackGroupBox);
CreatePlaybackControls(playbackGroupBox);
currentY += 120;
// 碰撞检测
GroupBox collisionGroupBox = new GroupBox
{
Text = "碰撞检测",
Location = new Point(10, currentY),
Size = new Size(320, 100),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(collisionGroupBox);
CreateCollisionControls(collisionGroupBox);
tabControl.TabPages.Add(animationTab);
}
/// <summary>
/// 创建系统管理Tab页
/// </summary>
private void CreateSystemManagementTab(TabControl tabControl)
{
TabPage systemTab = new TabPage("系统管理");
systemTab.Padding = new Padding(10);
Panel scrollPanel = new Panel
{
Dock = DockStyle.Fill,
AutoScroll = true
};
systemTab.Controls.Add(scrollPanel);
int currentY = 10;
// 日志管理
GroupBox logGroupBox = new GroupBox
{
Text = "日志管理",
Location = new Point(10, currentY),
Size = new Size(320, 120),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(logGroupBox);
CreateLogManagementControls(logGroupBox);
currentY += 140;
// 插件设置
GroupBox settingsGroupBox = new GroupBox
{
Text = "插件设置",
Location = new Point(10, currentY),
Size = new Size(320, 100),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(settingsGroupBox);
CreatePluginSettingsControls(settingsGroupBox);
currentY += 120;
// 系统信息
GroupBox systemInfoGroupBox = new GroupBox
{
Text = "系统信息",
Location = new Point(10, currentY),
Size = new Size(320, 150),
Font = new Font("微软雅黑", 8, FontStyle.Bold)
};
scrollPanel.Controls.Add(systemInfoGroupBox);
CreateSystemInfoControls(systemInfoGroupBox);
tabControl.TabPages.Add(systemTab);
}
/// <summary>
/// 创建路径列表管理控件
/// </summary>
private void CreatePathListManagement(GroupBox groupBox)
{
// 路径操作按钮
Button newButton = new Button
{
Text = "新建",
Location = new Point(15, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(newButton);
Button detailButton = new Button
{
Text = "详情",
Location = new Point(85, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(detailButton);
Button editButton = new Button
{
Text = "编辑",
Location = new Point(155, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(editButton);
Button deleteButton = new Button
{
Text = "删除",
Location = new Point(225, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(deleteButton);
// 路径列表
_pathListView = new ListView
{
Location = new Point(15, 60),
Size = new Size(290, 80),
View = System.Windows.Forms.View.Details,
FullRowSelect = true,
GridLines = true,
Font = new Font("微软雅黑", 8)
};
_pathListView.Columns.Add("路径名称", 150);
_pathListView.Columns.Add("创建时间", 80);
_pathListView.Columns.Add("点数", 50);
groupBox.Controls.Add(_pathListView);
// 添加事件处理
newButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info("[新建按钮] ===== 新建按钮被点击 =====");
var pathManager = PathPlanningManager.GetActivePathManager() ?? new PathPlanningManager();
LogManager.Info($"[新建按钮] 获取到路径管理器: {pathManager != null}");
// 开始创建新路径
var newRoute = pathManager.StartCreatingNewRoute();
LogManager.Info($"[新建按钮] StartCreatingNewRoute调用完成返回路径: {newRoute?.Name ?? "null"}");
if (newRoute != null)
{
// 更新UI状态显示
LogManager.Info("[新建按钮] 开始更新UI状态");
UpdateCurrentPathPointsList();
UpdatePathList();
LogManager.Info("[新建按钮] UI状态更新完成");
LogManager.Info("开始创建新路径,已进入创建状态");
MessageBox.Show("已进入新建路径模式!\n\n请在3D视图中点击物流通道来设置路径点。",
"新建路径", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
LogManager.Error("[新建按钮] 创建新路径失败");
MessageBox.Show("创建新路径失败,请查看日志", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
LogManager.Info("[新建按钮] ===== 新建按钮事件处理完成 =====");
}, "新建路径");
};
editButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
if (_pathListView.SelectedItems.Count == 0)
{
MessageBox.Show("请先选择要编辑的路径", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var selectedRouteName = _pathListView.SelectedItems[0].Text;
// 查找对应的路径对象
var pathManager = PathPlanningManager.GetActivePathManager() ?? new PathPlanningManager();
var routeToEdit = pathManager.Routes.FirstOrDefault(r => r.Name == selectedRouteName);
if (routeToEdit != null)
{
// 切换到编辑状态
pathManager.SwitchToEditingState(routeToEdit);
// 更新UI状态显示
UpdateCurrentPathPointsList();
UpdatePathList();
LogManager.Info($"开始编辑路径: {selectedRouteName}");
MessageBox.Show($"已进入编辑模式!\n\n正在编辑路径: {selectedRouteName}\n\n可以在3D视图中修改路径点。",
"编辑路径", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show($"找不到路径: {selectedRouteName}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}, "编辑路径");
};
deleteButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
if (_pathListView.SelectedItems.Count == 0)
{
MessageBox.Show("请先选择要删除的路径", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var result = MessageBox.Show($"确定要删除路径 '{_pathListView.SelectedItems[0].Text}' 吗?",
"确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
// TODO: 实现删除路径的逻辑
LogManager.Info($"删除路径: {_pathListView.SelectedItems[0].Text}");
_pathListView.SelectedItems[0].Remove();
MessageBox.Show("路径已删除", "操作完成",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}, "删除路径");
};
detailButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
if (_pathListView.SelectedItems.Count == 0)
{
MessageBox.Show("请先选择要查看的路径", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var selectedPath = _pathListView.SelectedItems[0];
var detailInfo = $"路径名称: {selectedPath.SubItems[0].Text}\n" +
$"创建时间: {selectedPath.SubItems[1].Text}\n" +
$"路径点数: {selectedPath.SubItems[2].Text}";
MessageBox.Show(detailInfo, "路径详情",
MessageBoxButtons.OK, MessageBoxIcon.Information);
LogManager.Info($"查看路径详情: {selectedPath.Text}");
}, "查看路径详情");
};
}
/// <summary>
/// 创建当前路径编辑控件
/// </summary>
private void CreateCurrentPathEditor(GroupBox groupBox)
{
// 状态显示
_currentPathStatusLabel = new Label
{
Text = "状态: 查看模式",
Location = new Point(15, 25),
Size = new Size(200, 20),
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.Blue
};
groupBox.Controls.Add(_currentPathStatusLabel);
// 说明文字
Label instructionLabel = new Label
{
Text = "在3D视图中点击物流通道设置路径点",
Location = new Point(15, 50),
Size = new Size(290, 20),
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.Gray
};
groupBox.Controls.Add(instructionLabel);
// 路径点列表
Label pointsLabel = new Label
{
Text = "路径点列表:",
Location = new Point(15, 80),
Size = new Size(80, 20),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(pointsLabel);
_currentPathPointsListView = new ListView
{
Location = new Point(15, 105),
Size = new Size(290, 100),
Font = new Font("微软雅黑", 8),
View = System.Windows.Forms.View.Details, // 设置为详细信息视图
FullRowSelect = true,
GridLines = true
};
// 添加列
_currentPathPointsListView.Columns.Add("序号", 40, HorizontalAlignment.Left);
_currentPathPointsListView.Columns.Add("名称", 80, HorizontalAlignment.Left);
_currentPathPointsListView.Columns.Add("类型", 60, HorizontalAlignment.Left);
_currentPathPointsListView.Columns.Add("坐标 (X,Y,Z)", 110, HorizontalAlignment.Left);
groupBox.Controls.Add(_currentPathPointsListView);
// 操作按钮
Button finishButton = new Button
{
Text = "完成编辑",
Location = new Point(120, 215),
Size = new Size(80, 25),
Font = new Font("微软雅黑", 8),
Enabled = false
};
groupBox.Controls.Add(finishButton);
Button cancelButton = new Button
{
Text = "取消编辑",
Location = new Point(210, 215),
Size = new Size(80, 25),
Font = new Font("微软雅黑", 8),
Enabled = false
};
groupBox.Controls.Add(cancelButton);
// 添加事件处理
finishButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager == null)
{
MessageBox.Show("路径管理器未初始化", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (!pathManager.IsInEditableState)
{
MessageBox.Show("当前不在编辑状态", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 完成编辑并保存
bool success = pathManager.FinishEditing();
if (success)
{
// 更新UI状态显示
UpdateCurrentPathPointsList();
UpdatePathList();
LogManager.Info("路径编辑已完成并保存");
MessageBox.Show("路径编辑完成!", "操作完成",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("完成编辑时发生错误,请查看日志", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}, "完成编辑");
};
cancelButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager == null)
{
MessageBox.Show("路径管理器未初始化", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (!pathManager.IsInEditableState)
{
MessageBox.Show("当前不在编辑状态", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var result = MessageBox.Show("确定要取消编辑吗?未保存的更改将丢失。",
"确认取消", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
// 取消编辑并清理临时数据
bool success = pathManager.CancelEditing();
if (success)
{
// 更新UI状态显示
UpdateCurrentPathPointsList();
UpdatePathList();
LogManager.Info("路径编辑已取消");
MessageBox.Show("已取消编辑", "操作完成",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("取消编辑时发生错误,请查看日志", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}, "取消编辑");
};
}
/// <summary>
/// 创建路径文件管理控件
/// </summary>
private void CreatePathFileManagement(GroupBox groupBox)
{
Button saveButton = new Button
{
Text = "保存当前路径",
Location = new Point(15, 25),
Size = new Size(90, 30),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(saveButton);
Button importButton = new Button
{
Text = "导入路径",
Location = new Point(115, 25),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(importButton);
Button exportButton = new Button
{
Text = "导出路径",
Location = new Point(205, 25),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(exportButton);
Button historyButton = new Button
{
Text = "查看历史",
Location = new Point(15, 65),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(historyButton);
// 添加事件处理
saveButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager?.CurrentRoute?.Points == null || pathManager.CurrentRoute.Points.Count == 0)
{
MessageBox.Show("当前没有可保存的路径", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 显示保存对话框
SaveFileDialog saveDialog = new SaveFileDialog
{
Title = "保存路径文件",
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json",
FilterIndex = 1,
DefaultExt = "xml"
};
if (saveDialog.ShowDialog() == DialogResult.OK)
{
bool saveResult = false;
var extension = System.IO.Path.GetExtension(saveDialog.FileName).ToLowerInvariant();
if (extension == ".json")
{
saveResult = PathFileSerializer.SaveToJson(pathManager.CurrentRoute, saveDialog.FileName);
}
else
{
saveResult = PathFileSerializer.SaveToXml(pathManager.CurrentRoute, saveDialog.FileName);
}
if (saveResult)
{
// 保存到历史记录
pathManager.SaveCurrentRouteToHistory($"手动保存到文件: {System.IO.Path.GetFileName(saveDialog.FileName)}");
LogManager.Info($"路径成功保存到: {saveDialog.FileName}");
MessageBox.Show($"路径已保存到: {saveDialog.FileName}", "保存成功",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
LogManager.Error($"保存路径失败: {saveDialog.FileName}");
MessageBox.Show("保存路径失败,请检查文件路径和权限", "保存失败",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}, "保存当前路径");
};
importButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager == null)
{
MessageBox.Show("路径管理器未初始化", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
OpenFileDialog openDialog = new OpenFileDialog
{
Title = "导入路径文件",
Filter = "路径文件 (*.xml;*.json)|*.xml;*.json|XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
FilterIndex = 1
};
if (openDialog.ShowDialog() == DialogResult.OK)
{
PathRoute importedRoute = null;
var fileFormat = PathFileSerializer.DetectFileFormat(openDialog.FileName);
switch (fileFormat)
{
case "XML":
importedRoute = PathFileSerializer.LoadFromXml(openDialog.FileName);
break;
case "JSON":
importedRoute = PathFileSerializer.LoadFromJson(openDialog.FileName);
if (importedRoute == null)
{
MessageBox.Show("JSON格式导入功能简化建议使用XML格式", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
break;
default:
MessageBox.Show($"不支持的文件格式: {fileFormat}", "导入失败",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (importedRoute != null && importedRoute.Points.Count > 0)
{
// 添加到路径管理器
pathManager.AddRoute(importedRoute);
pathManager.CurrentRoute = importedRoute;
LogManager.Info($"成功导入路径: {importedRoute.Name},包含 {importedRoute.Points.Count} 个路径点");
MessageBox.Show($"路径 '{importedRoute.Name}' 已成功导入,包含 {importedRoute.Points.Count} 个路径点", "导入成功",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
LogManager.Error($"导入路径失败: {openDialog.FileName}");
MessageBox.Show("导入路径失败,文件格式可能不正确", "导入失败",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}, "导入路径");
};
exportButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager?.CurrentRoute?.Points == null || pathManager.CurrentRoute.Points.Count == 0)
{
MessageBox.Show("当前没有可导出的路径", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
SaveFileDialog exportDialog = new SaveFileDialog
{
Title = "导出路径文件",
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json",
FilterIndex = 1,
DefaultExt = "xml"
};
if (exportDialog.ShowDialog() == DialogResult.OK)
{
bool exportResult = false;
var extension = System.IO.Path.GetExtension(exportDialog.FileName).ToLowerInvariant();
if (extension == ".json")
{
exportResult = PathFileSerializer.SaveToJson(pathManager.CurrentRoute, exportDialog.FileName);
}
else
{
exportResult = PathFileSerializer.SaveToXml(pathManager.CurrentRoute, exportDialog.FileName);
}
if (exportResult)
{
LogManager.Info($"路径成功导出到: {exportDialog.FileName}");
MessageBox.Show($"路径已导出到: {exportDialog.FileName}", "导出成功",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
LogManager.Error($"导出路径失败: {exportDialog.FileName}");
MessageBox.Show("导出路径失败,请检查文件路径和权限", "导出失败",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}, "导出路径");
};
historyButton.Click += (sender, e) => {
GlobalExceptionHandler.SafeExecute(() =>
{
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager?.HistoryManager == null)
{
MessageBox.Show("历史记录管理器未初始化", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var historyEntries = pathManager.HistoryManager.GetAllHistoryEntries();
if (historyEntries.Count == 0)
{
MessageBox.Show("暂无历史记录", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 显示历史记录窗口
ShowPathHistoryDialog(historyEntries, pathManager.HistoryManager);
}, "查看历史记录");
};
}
/// <summary>
/// 创建播放控制控件
/// </summary>
private void CreatePlaybackControls(GroupBox groupBox)
{
Button playButton = new Button
{
Text = "▶ 播放",
Location = new Point(15, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(playButton);
Button pauseButton = new Button
{
Text = "⏸ 暂停",
Location = new Point(85, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(pauseButton);
Button stopButton = new Button
{
Text = "⏹ 停止",
Location = new Point(155, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(stopButton);
Button resetButton = new Button
{
Text = "🔄 重置",
Location = new Point(225, 25),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(resetButton);
// 进度条
ProgressBar progressBar = new ProgressBar
{
Location = new Point(15, 65),
Size = new Size(270, 15)
};
groupBox.Controls.Add(progressBar);
// 事件处理
playButton.Click += (sender, e) =>
{
if (_animationManager != null)
{
_animationManager.StartAnimation();
LogManager.Info("动画播放开始");
}
};
pauseButton.Click += (sender, e) =>
{
LogManager.Info("动画暂停(功能待实现)");
};
stopButton.Click += (sender, e) =>
{
if (_animationManager != null)
{
_animationManager.StopAnimation();
LogManager.Info("动画停止");
}
};
resetButton.Click += (sender, e) =>
{
if (_animationManager != null)
{
_animationManager.ResetAnimation();
LogManager.Info("动画重置");
}
};
}
/// <summary>
/// 更新物流统计信息
/// </summary>
private void UpdateLogisticsStats(Label statsLabel)
{
GlobalExceptionHandler.SafeExecute(() =>
{
var document = NavisApplication.ActiveDocument;
if (document?.Models == null)
{
statsLabel.Text = "统计: 无活动文档";
return;
}
int totalModels = 0;
int logisticsModels = 0;
// 统计所有模型和物流模型
foreach (ModelItem rootItem in document.Models.RootItems)
{
foreach (ModelItem item in rootItem.DescendantsAndSelf)
{
totalModels++;
if (CategoryAttributeManager.HasLogisticsAttributes(item))
{
logisticsModels++;
}
}
}
statsLabel.Text = $"统计: 总模型 {totalModels} 个,物流模型 {logisticsModels} 个";
}, "更新物流统计");
}
/// <summary>
/// 刷新物流模型列表
/// </summary>
private void RefreshLogisticsModelList(ListView listView)
{
GlobalExceptionHandler.SafeExecute(() =>
{
listView.Items.Clear();
var document = NavisApplication.ActiveDocument;
if (document?.Models == null) return;
foreach (ModelItem rootItem in document.Models.RootItems)
{
foreach (ModelItem item in rootItem.DescendantsAndSelf)
{
if (CategoryAttributeManager.HasLogisticsAttributes(item))
{
var category = CategoryAttributeManager.GetLogisticsPropertyValue(item, CategoryAttributeManager.LogisticsProperties.TYPE);
var listItem = new ListViewItem(new string[]
{
item.DisplayName.Length > 25 ? item.DisplayName.Substring(0, 25) + "..." : item.DisplayName,
string.IsNullOrEmpty(category) ? "未知" : category
});
listItem.Tag = item; // 保存ModelItem引用
listView.Items.Add(listItem);
}
}
}
LogManager.Info($"物流模型列表已刷新,共 {listView.Items.Count} 项");
}, "刷新物流模型列表");
}
/// <summary>
/// 编辑选中的物流模型
/// </summary>
private void EditSelectedLogisticsModel(ListView listView)
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (listView.SelectedItems.Count == 0)
{
MessageBox.Show("请先选择要修改的物流模型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var selectedItem = listView.SelectedItems[0];
var modelItem = selectedItem.Tag as ModelItem;
if (modelItem != null)
{
// 这里可以打开一个编辑对话框,暂时用简单的消息框演示
var result = MessageBox.Show($"是否将模型 '{modelItem.DisplayName}' 的类别改为通道?",
"修改物流类别", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
// 创建包含该模型的集合,然后添加物流属性
var items = new ModelItemCollection();
items.Add(modelItem);
CategoryAttributeManager.AddLogisticsAttributes(items, CategoryAttributeManager.LogisticsElementType.);
// 设置为绿色标记
var navisColor = new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 绿色
NavisApplication.ActiveDocument.Models.OverrideTemporaryColor(new ModelItem[] { modelItem }, navisColor);
RefreshLogisticsModelList(listView);
LogManager.Info($"已将模型 {modelItem.DisplayName} 设置为通道类别并标记为绿色");
}
}
}, "编辑物流模型");
}
/// <summary>
/// 清除选中模型的物流属性
/// </summary>
private void ClearSelectedLogisticsModel(ListView listView)
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (listView.SelectedItems.Count == 0)
{
MessageBox.Show("请先选择要清除的物流模型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var selectedItem = listView.SelectedItems[0];
var modelItem = selectedItem.Tag as ModelItem;
if (modelItem != null)
{
var result = MessageBox.Show($"是否清除模型 '{modelItem.DisplayName}' 的物流属性?\n\n注意当前版本暂不支持删除已设置的物流属性只能重置显示颜色。",
"清除物流属性", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
// 注意目前CategoryAttributeManager类中没有清除属性的方法
// 作为临时方案,只重置颜色显示
// 重置颜色
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
RefreshLogisticsModelList(listView);
LogManager.Info($"已重置模型 {modelItem.DisplayName} 的显示颜色(物流属性仍保留)");
MessageBox.Show("已重置显示颜色。\n注意物流属性数据仍保留在模型中。", "操作完成", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}, "清除物流属性");
}
/// <summary>
/// 高亮显示选中的物流模型
/// </summary>
private void HighlightSelectedLogisticsModel(ListView listView)
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (listView.SelectedItems.Count == 0)
{
MessageBox.Show("请先选择要高亮的物流模型", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var selectedItem = listView.SelectedItems[0];
var modelItem = selectedItem.Tag as ModelItem;
if (modelItem != null)
{
// 先重置所有颜色
NavisApplication.ActiveDocument.Models.ResetAllTemporaryMaterials();
// 高亮选中的模型(黄色)
var highlightColor = new Autodesk.Navisworks.Api.Color(1.0, 1.0, 0.0); // 黄色
NavisApplication.ActiveDocument.Models.OverrideTemporaryColor(new ModelItem[] { modelItem }, highlightColor);
// 选中该模型
NavisApplication.ActiveDocument.CurrentSelection.Clear();
NavisApplication.ActiveDocument.CurrentSelection.Add(modelItem);
LogManager.Info($"已高亮显示模型 {modelItem.DisplayName}");
}
}, "高亮物流模型");
}
/// <summary>
/// 创建物流模型列表
/// </summary>
private void CreateLogisticsModelList(GroupBox parent)
{
GlobalExceptionHandler.SafeExecute(() =>
{
// 创建列表视图(保存引用)
_logisticsListView = new ListView
{
Location = new Point(10, 20),
Size = new Size(320, 120),
View = System.Windows.Forms.View.Details,
FullRowSelect = true,
GridLines = true,
Font = new Font("微软雅黑", 8)
};
// 添加列标题
_logisticsListView.Columns.Add("模型名称", 180);
_logisticsListView.Columns.Add("物流类型", 120);
parent.Controls.Add(_logisticsListView);
// 操作按钮区域
Button refreshButton = new Button
{
Text = "刷新列表",
Size = new Size(70, 25),
Location = new Point(10, 150),
Font = new Font("微软雅黑", 8)
};
parent.Controls.Add(refreshButton);
Button editButton = new Button
{
Text = "修改类别",
Size = new Size(70, 25),
Location = new Point(90, 150),
Font = new Font("微软雅黑", 8)
};
parent.Controls.Add(editButton);
Button clearButton = new Button
{
Text = "清除属性",
Size = new Size(70, 25),
Location = new Point(170, 150),
Font = new Font("微软雅黑", 8)
};
parent.Controls.Add(clearButton);
Button highlightButton = new Button
{
Text = "高亮显示",
Size = new Size(70, 25),
Location = new Point(250, 150),
Font = new Font("微软雅黑", 8)
};
parent.Controls.Add(highlightButton);
// 事件处理(使用静态方法)
refreshButton.Click += (sender, e) => RefreshLogisticsModelListStatic(_logisticsListView);
editButton.Click += (sender, e) => EditSelectedLogisticsModel(_logisticsListView);
clearButton.Click += (sender, e) => ClearSelectedLogisticsModel(_logisticsListView);
highlightButton.Click += (sender, e) => HighlightSelectedLogisticsModel(_logisticsListView);
// 初始加载
RefreshLogisticsModelListStatic(_logisticsListView);
}, "创建物流模型列表");
}
/// <summary>
/// 更新物流统计信息
/// </summary>
private void CreateCollisionControls(GroupBox groupBox)
{
CheckBox enableCollisionCheckBox = new CheckBox
{
Text = "启用碰撞检测",
Location = new Point(15, 25),
Checked = true,
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(enableCollisionCheckBox);
CheckBox highlightCheckBox = new CheckBox
{
Text = "高亮显示碰撞",
Location = new Point(150, 25),
Checked = true,
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(highlightCheckBox);
Label collisionStatusLabel = new Label
{
Text = "碰撞状态: 未检测",
Location = new Point(15, 55),
Size = new Size(200, 20),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(collisionStatusLabel);
}
/// <summary>
/// 创建日志管理控件
/// </summary>
private void CreateLogManagementControls(GroupBox groupBox)
{
Button viewLogButton = new Button
{
Text = "查看日志",
Location = new Point(15, 25),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(viewLogButton);
Button clearLogButton = new Button
{
Text = "清空日志",
Location = new Point(105, 25),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(clearLogButton);
Button exportLogButton = new Button
{
Text = "导出日志",
Location = new Point(195, 25),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(exportLogButton);
ComboBox logLevelCombo = new ComboBox
{
Location = new Point(15, 65),
Size = new Size(120, 25),
DropDownStyle = ComboBoxStyle.DropDownList,
Font = new Font("微软雅黑", 8)
};
logLevelCombo.Items.AddRange(new[] { "详细", "信息", "警告", "错误" });
logLevelCombo.SelectedIndex = 1;
groupBox.Controls.Add(logLevelCombo);
Label logLevelLabel = new Label
{
Text = "日志级别:",
Location = new Point(145, 68),
Size = new Size(60, 20),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(logLevelLabel);
// 事件处理
viewLogButton.Click += (sender, e) =>
{
string logPath = LogManager.LogFilePath;
if (System.IO.File.Exists(logPath))
{
System.Diagnostics.Process.Start("notepad.exe", logPath);
}
else
{
MessageBox.Show("日志文件不存在", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
};
clearLogButton.Click += (sender, e) =>
{
if (MessageBox.Show("确定要清空所有日志吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
LogManager.ClearLog();
MessageBox.Show("日志已清空", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
};
}
/// <summary>
/// 创建插件设置控件
/// </summary>
private void CreatePluginSettingsControls(GroupBox groupBox)
{
CheckBox autoSaveCheckBox = new CheckBox
{
Text = "自动保存路径",
Location = new Point(15, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(autoSaveCheckBox);
CheckBox debugModeCheckBox = new CheckBox
{
Text = "调试模式",
Location = new Point(150, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(debugModeCheckBox);
Button resetSettingsButton = new Button
{
Text = "重置设置",
Location = new Point(15, 55),
Size = new Size(80, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(resetSettingsButton);
}
/// <summary>
/// 创建系统信息控件
/// </summary>
private void CreateSystemInfoControls(GroupBox groupBox)
{
Label versionLabel = new Label
{
Text = "插件版本: v1.0",
Location = new Point(15, 25),
Size = new Size(150, 20),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(versionLabel);
Label navisVersionLabel = new Label
{
Text = $"Navisworks版本: {NavisApplication.Version}",
Location = new Point(15, 50),
Size = new Size(200, 20),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(navisVersionLabel);
Label osLabel = new Label
{
Text = $"操作系统: {Environment.OSVersion}",
Location = new Point(15, 75),
Size = new Size(300, 20),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(osLabel);
Label memoryLabel = new Label
{
Text = $"内存使用: {GC.GetTotalMemory(false) / 1024 / 1024} MB",
Location = new Point(15, 100),
Size = new Size(200, 20),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(memoryLabel);
Button refreshInfoButton = new Button
{
Text = "刷新信息",
Location = new Point(15, 120),
Size = new Size(80, 25),
Font = new Font("微软雅黑", 8)
};
groupBox.Controls.Add(refreshInfoButton);
refreshInfoButton.Click += (sender, e) =>
{
memoryLabel.Text = $"内存使用: {GC.GetTotalMemory(false) / 1024 / 1024} MB";
};
}
/// <summary>
/// 创建3D交互控制界面
/// </summary>
/// <param name="parent">父容器</param>
/// <summary>
/// 创建路径管理控制界面
/// </summary>
/// <param name="parent">父容器</param>
private void CreatePathManagementControls(GroupBox parent)
{
// 导入路径按钮
Button importPathButton = new Button
{
Text = "导入路径",
Size = new Size(100, 30),
Location = new Point(20, 25),
Font = new Font("微软雅黑", 8),
UseVisualStyleBackColor = true
};
// 导出路径按钮
Button exportPathButton = new Button
{
Text = "导出路径",
Size = new Size(100, 30),
Location = new Point(130, 25),
Font = new Font("微软雅黑", 8),
UseVisualStyleBackColor = true
};
// 路径历史按钮
Button pathHistoryButton = new Button
{
Text = "路径历史",
Size = new Size(100, 30),
Location = new Point(240, 25),
Font = new Font("微软雅黑", 8),
UseVisualStyleBackColor = true
};
// 事件处理
importPathButton.Click += (sender, e) =>
{
try
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Title = "选择路径文件",
Filter = "XML文件 (*.xml)|*.xml|JSON文件 (*.json)|*.json|所有文件 (*.*)|*.*",
FilterIndex = 1
};
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
var dataManager = new PathDataManager();
var routes = new List<PathRoute>();
string extension = System.IO.Path.GetExtension(openFileDialog.FileName).ToLower();
if (extension == ".xml")
{
routes = dataManager.ImportFromXml(openFileDialog.FileName);
}
else if (extension == ".json")
{
routes = dataManager.ImportFromJson(openFileDialog.FileName);
}
if (routes.Count > 0)
{
MessageBox.Show($"成功导入 {routes.Count} 条路径", "导入成功",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show("文件中未找到有效的路径数据", "导入提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
catch (Exception ex)
{
MessageBox.Show($"导入路径失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
};
exportPathButton.Click += (sender, e) =>
{
MessageBox.Show("导出功能正在开发中", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
};
pathHistoryButton.Click += (sender, e) =>
{
MessageBox.Show("路径历史功能正在开发中", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
};
// 添加控件到父容器
parent.Controls.Add(importPathButton);
parent.Controls.Add(exportPathButton);
parent.Controls.Add(pathHistoryButton);
}
/// <summary>
/// 创建类别选择下拉框
/// </summary>
/// <param name="parent">父容器</param>
private void CreateCategoryDropdown(GroupBox parent)
{
// 类别标签
Label categoryLabel = new Label
{
Text = "设为类型:",
Location = new Point(10, 30),
Size = new Size(60, 20),
Font = new Font("微软雅黑", 8)
};
parent.Controls.Add(categoryLabel);
// 类别下拉框
ComboBox categoryComboBox = new ComboBox
{
Location = new Point(80, 25),
Size = new Size(80, 25),
Font = new Font("微软雅黑", 8),
DropDownStyle = ComboBoxStyle.DropDownList
};
// 添加类别选项
categoryComboBox.Items.Add("门");
categoryComboBox.Items.Add("电梯");
categoryComboBox.Items.Add("楼梯");
categoryComboBox.Items.Add("通道");
categoryComboBox.Items.Add("障碍物");
categoryComboBox.Items.Add("装卸区");
categoryComboBox.Items.Add("停车位");
categoryComboBox.Items.Add("检查点");
categoryComboBox.SelectedIndex = 3; // 默认选择"通道"
parent.Controls.Add(categoryComboBox);
// 应用按钮
Button applyButton = new Button
{
Text = "应用类别",
Location = new Point(170, 25),
Size = new Size(80, 25),
Font = new Font("微软雅黑", 8),
UseVisualStyleBackColor = true
};
// 应用按钮点击事件
applyButton.Click += (sender, e) =>
{
try
{
if (categoryComboBox.SelectedIndex < 0)
{
MessageBox.Show("请先选择一个类别", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 获取当前选中的模型项
ModelItemCollection selectedItems = NavisApplication.ActiveDocument.CurrentSelection.SelectedItems;
if (selectedItems.Count == 0)
{
MessageBox.Show("请先选择要设置属性的模型项", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 将下拉框选择转换为枚举类型
CategoryAttributeManager.LogisticsElementType elementType;
switch (categoryComboBox.SelectedIndex)
{
case 0: elementType = CategoryAttributeManager.LogisticsElementType.; break;
case 1: elementType = CategoryAttributeManager.LogisticsElementType.; break;
case 2: elementType = CategoryAttributeManager.LogisticsElementType.; break;
case 3: elementType = CategoryAttributeManager.LogisticsElementType.; break;
case 4: elementType = CategoryAttributeManager.LogisticsElementType.; break;
case 5: elementType = CategoryAttributeManager.LogisticsElementType.; break;
case 6: elementType = CategoryAttributeManager.LogisticsElementType.; break;
case 7: elementType = CategoryAttributeManager.LogisticsElementType.; break;
default: elementType = CategoryAttributeManager.LogisticsElementType.; break;
}
// 执行属性添加操作
int successCount = CategoryAttributeManager.AddLogisticsAttributes(
selectedItems,
elementType,
elementType != CategoryAttributeManager.LogisticsElementType., // 障碍物默认不可通行
5, // 默认优先级
"标准", // 默认车辆尺寸
10.0 // 默认速度限制
);
// 显示结果
if (successCount > 0)
{
// 设置为绿色标记(视觉反馈)
var navisColor = new Autodesk.Navisworks.Api.Color(0.0, 1.0, 0.0); // 绿色
NavisApplication.ActiveDocument.Models.OverrideTemporaryColor(selectedItems.ToArray(), navisColor);
// 自动刷新界面数据
RefreshInterfaceData();
LogManager.Info($"已为 {successCount} 个模型设置物流属性: {categoryComboBox.SelectedItem}");
}
else
{
MessageBox.Show("未能为任何模型项设置属性,请检查选择的模型项", "操作失败",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
catch (Exception ex)
{
MessageBox.Show($"设置属性时发生错误: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
LogManager.Error($"设置物流属性失败: {ex.Message}");
}
};
parent.Controls.Add(applyButton);
}
/// <summary>
/// 创建动画控制界面
/// </summary>
/// <param name="parent">父容器</param>
private void CreateAnimationControls(GroupBox parent)
{
// 部件选择部分
Label vehicleInstructionLabel = new Label
{
Text = "请在选择树中选择部件",
Location = new Point(20, 25),
Size = new Size(200, 20),
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.Blue
};
Button getVehicleButton = new Button
{
Text = "获取选中部件",
Location = new Point(230, 22),
Size = new Size(90, 27),
Font = new Font("微软雅黑", 8),
BackColor = System.Drawing.Color.LightBlue,
UseVisualStyleBackColor = false
};
Label vehicleStatusLabel = new Label
{
Text = "状态: 未选择",
Location = new Point(20, 55),
Size = new Size(300, 20),
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.Gray
};
// 路径选择部分
Label pathLabel = new Label
{
Text = "路径选择:",
Location = new Point(20, 85),
Size = new Size(70, 20),
Font = new Font("微软雅黑", 8)
};
ComboBox pathComboBox = new ComboBox
{
Location = new Point(95, 83),
Size = new Size(150, 25),
Font = new Font("微软雅黑", 8),
DropDownStyle = ComboBoxStyle.DropDownList,
DisplayMember = "Name" // 显示路径的Name属性
};
Label pathInfoLabel = new Label
{
Text = "点数: 0",
Location = new Point(255, 87),
Size = new Size(60, 20),
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.Gray
};
Button refreshPathButton = new Button
{
Text = "刷新",
Location = new Point(320, 83),
Size = new Size(50, 25),
Font = new Font("微软雅黑", 8),
UseVisualStyleBackColor = true
};
// 动画持续时间设置
Label durationLabel = new Label
{
Text = "动画时长(秒):",
Location = new Point(20, 115),
Size = new Size(80, 20),
Font = new Font("微软雅黑", 8)
};
NumericUpDown durationNumeric = new NumericUpDown
{
Location = new Point(105, 113),
Size = new Size(60, 25),
Font = new Font("微软雅黑", 8),
Minimum = 1,
Maximum = 300,
Value = 10,
DecimalPlaces = 1
};
// 生成动画按钮
Button createAnimationButton = new Button
{
Text = "生成动画",
Location = new Point(175, 112),
Size = new Size(75, 27),
Font = new Font("微软雅黑", 8),
BackColor = System.Drawing.Color.LightGreen,
UseVisualStyleBackColor = false,
Enabled = false
};
// 播放控制按钮
Button startAnimationButton = new Button
{
Text = "播放",
Location = new Point(260, 112),
Size = new Size(60, 27),
Font = new Font("微软雅黑", 8),
Enabled = false
};
Button stopAnimationButton = new Button
{
Text = "停止",
Location = new Point(20, 145),
Size = new Size(60, 27),
Font = new Font("微软雅黑", 8),
Enabled = false
};
Button resetAnimationButton = new Button
{
Text = "重置",
Location = new Point(90, 145),
Size = new Size(60, 27),
Font = new Font("微软雅黑", 8),
Enabled = false
};
// 动画状态显示
Label statusLabel = new Label
{
Text = "状态: 未生成动画",
Location = new Point(160, 149),
Size = new Size(160, 20),
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.Gray
};
// 存储选中的部件
ModelItem selectedComponent = null;
// 车辆选择事件处理
getVehicleButton.Click += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
var doc = NavisApplication.ActiveDocument;
var selectedItems = doc.CurrentSelection.SelectedItems;
if (selectedItems.Count == 0)
{
MessageBox.Show("请先在选择树中选择一个部件", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (selectedItems.Count > 1)
{
MessageBox.Show("请只选择一个部件", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
selectedComponent = selectedItems.First;
vehicleStatusLabel.Text = $"状态: 已选择 {selectedComponent.DisplayName}";
vehicleStatusLabel.ForeColor = System.Drawing.Color.Green;
// 检查是否可以启用生成动画按钮
if (pathComboBox.SelectedItem != null)
{
createAnimationButton.Enabled = true;
}
}, "获取选中部件");
};
// 路径选择事件处理
pathComboBox.SelectedIndexChanged += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (pathComboBox.SelectedItem != null)
{
var selectedPath = pathComboBox.SelectedItem as PathRoute;
if (selectedPath != null)
{
pathInfoLabel.Text = $"点数: {selectedPath.Points?.Count ?? 0}";
// 检查是否可以启用生成动画按钮
if (selectedComponent != null)
{
createAnimationButton.Enabled = true;
}
}
}
else
{
pathInfoLabel.Text = "点数: 0";
createAnimationButton.Enabled = false;
}
}, "路径选择变化");
};
// 初始化路径下拉框
var refreshPathList = new Action(() =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
pathComboBox.Items.Clear();
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager?.Routes != null)
{
foreach (var route in pathManager.Routes)
{
pathComboBox.Items.Add(route);
}
LogManager.Info($"动画控制面板:已刷新路径列表,共{pathManager.Routes.Count}条路径");
}
else
{
LogManager.Info("动画控制面板:未找到路径管理器或路径列表为空");
}
}, "刷新路径列表");
});
refreshPathList(); // 初始加载
// 监听路径生成事件,自动刷新路径列表
var activePathManager = PathPlanningManager.GetActivePathManager();
if (activePathManager != null)
{
activePathManager.RouteGenerated += (sender, route) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info($"检测到新路径生成:{route?.Name},自动刷新动画控制面板路径列表");
refreshPathList();
}, "路径生成事件处理");
};
}
// 刷新路径按钮事件处理
refreshPathButton.Click += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
refreshPathList();
MessageBox.Show("路径列表已刷新", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}, "刷新路径列表");
};
// 生成动画事件处理
createAnimationButton.Click += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (selectedComponent == null)
{
MessageBox.Show("请先选择部件模型", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
var selectedPath = pathComboBox.SelectedItem as PathRoute;
if (selectedPath?.Points == null || selectedPath.Points.Count < 2)
{
MessageBox.Show("请选择有效的路径至少2个点", "提示",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
// 创建动画管理器(如果还没有)
if (_animationManager == null)
{
_animationManager = new PathAnimationManager();
// 监听动画完成事件
_animationManager.AnimationCompleted += (animSender, animArgs) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
// 动画自动完成时更新UI状态
statusLabel.Text = "状态: 动画播放完成";
statusLabel.ForeColor = System.Drawing.Color.Green;
startAnimationButton.Enabled = true;
stopAnimationButton.Enabled = false;
createAnimationButton.Enabled = true;
LogManager.Info("动画自动完成UI状态已更新");
}, "动画完成事件处理");
};
// 快速测试TimeLiner API可选功能
bool timelineAvailable = _animationManager.TestTimeLinerAPI();
if (timelineAvailable)
{
LogManager.Info("TimeLiner API可用但当前使用Timer方案");
}
}
// 设置动画参数
var pathPoints = selectedPath.Points.Select(p => p.Position).ToList();
double duration = (double)durationNumeric.Value;
// 使用简化的动画设置方法
bool success = _animationManager.SetupSimpleAnimation(selectedComponent, pathPoints, duration);
if (!success)
{
MessageBox.Show("动画生成失败,请检查部件和路径设置", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
statusLabel.Text = "状态: 动画已生成";
statusLabel.ForeColor = System.Drawing.Color.Green;
// 启用播放控制按钮
startAnimationButton.Enabled = true;
resetAnimationButton.Enabled = true;
createAnimationButton.Enabled = false;
MessageBox.Show($"动画生成成功!\n部件: {selectedComponent.DisplayName}\n路径: {selectedPath.Name}\n路径点: {pathPoints.Count}个\n时长: {duration}秒",
"生成成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}, "生成动画");
};
startAnimationButton.Click += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (_animationManager != null)
{
_animationManager.StartAnimation();
statusLabel.Text = "状态: 动画播放中";
statusLabel.ForeColor = System.Drawing.Color.Blue;
startAnimationButton.Enabled = false;
stopAnimationButton.Enabled = true;
createAnimationButton.Enabled = false;
}
}, "播放动画");
};
stopAnimationButton.Click += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (_animationManager != null)
{
_animationManager.StopAnimation();
statusLabel.Text = "状态: 动画已停止";
statusLabel.ForeColor = System.Drawing.Color.Orange;
startAnimationButton.Enabled = true;
stopAnimationButton.Enabled = false;
createAnimationButton.Enabled = true;
}
}, "停止动画");
};
resetAnimationButton.Click += (sender, e) =>
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (_animationManager != null)
{
_animationManager.ResetAnimation();
statusLabel.Text = "状态: 动画已重置";
statusLabel.ForeColor = System.Drawing.Color.Gray;
startAnimationButton.Enabled = true;
stopAnimationButton.Enabled = false;
createAnimationButton.Enabled = true;
}
}, "重置动画");
};
// 添加控件到父容器
parent.Controls.Add(vehicleInstructionLabel);
parent.Controls.Add(getVehicleButton);
parent.Controls.Add(vehicleStatusLabel);
parent.Controls.Add(pathLabel);
parent.Controls.Add(pathComboBox);
parent.Controls.Add(pathInfoLabel);
parent.Controls.Add(refreshPathButton);
parent.Controls.Add(durationLabel);
parent.Controls.Add(durationNumeric);
parent.Controls.Add(createAnimationButton);
parent.Controls.Add(startAnimationButton);
parent.Controls.Add(stopAnimationButton);
parent.Controls.Add(resetAnimationButton);
parent.Controls.Add(statusLabel);
}
/// <summary>
/// 创建可见性控制界面
/// </summary>
/// <param name="parent">父容器</param>
private void CreateVisibilityControls(GroupBox parent)
{
// 只显示物流分类项目复选框
CheckBox logisticsOnlyCheckBox = new CheckBox
{
Text = "只显示物流分类项目",
Size = new Size(200, 20),
Location = new Point(20, 30),
Font = new Font("微软雅黑", 8),
Checked = false,
UseVisualStyleBackColor = true
};
// 状态标签
Label statusLabel = new Label
{
Text = "状态: 显示所有项目",
Location = new Point(20, 70),
Size = new Size(250, 20),
Font = new Font("微软雅黑", 8),
ForeColor = System.Drawing.Color.DarkGreen
};
// 复选框事件处理
logisticsOnlyCheckBox.CheckedChanged += (sender, e) =>
{
try
{
logisticsOnlyCheckBox.Enabled = false;
statusLabel.Text = "状态: 正在处理...";
statusLabel.ForeColor = System.Drawing.Color.Orange;
VisibilityOperationResult result;
if (logisticsOnlyCheckBox.Checked)
{
// 勾选时:隐藏非物流分类项目
result = VisibilityManager.HideNonLogisticsItems();
if (result.Success)
{
statusLabel.Text = $"状态: 已隐藏 {result.HiddenCount} 个非物流项目";
statusLabel.ForeColor = System.Drawing.Color.DarkGreen;
}
else
{
statusLabel.Text = "状态: 隐藏操作失败";
statusLabel.ForeColor = System.Drawing.Color.Red;
logisticsOnlyCheckBox.Checked = false; // 回滚状态
}
}
else
{
// 取消勾选时:显示所有项目
result = VisibilityManager.ShowAllItems();
if (result.Success)
{
statusLabel.Text = "状态: 显示所有项目";
statusLabel.ForeColor = System.Drawing.Color.DarkGreen;
}
else
{
statusLabel.Text = "状态: 显示操作失败";
statusLabel.ForeColor = System.Drawing.Color.Red;
logisticsOnlyCheckBox.Checked = true; // 回滚状态
}
}
// 如果操作失败,显示错误信息
if (!result.Success)
{
MessageBox.Show(result.Message, "操作失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
catch (Exception ex)
{
statusLabel.Text = "状态: 发生错误";
statusLabel.ForeColor = System.Drawing.Color.Red;
logisticsOnlyCheckBox.Checked = !logisticsOnlyCheckBox.Checked; // 回滚状态
MessageBox.Show($"操作出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
logisticsOnlyCheckBox.Enabled = true;
}
};
// 添加控件到父容器
parent.Controls.Add(logisticsOnlyCheckBox);
parent.Controls.Add(statusLabel);
}
/// <summary>
/// 选择变化事件处理
/// </summary>
private static void OnSelectionChanged(object sender, EventArgs e)
{
GlobalExceptionHandler.SafeExecute(() =>
{
// 更新选择显示
UpdateSelectionDisplay();
}, "选择变化事件处理");
}
/// <summary>
/// 更新选择显示信息
/// </summary>
private static void UpdateSelectionDisplay()
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (_controlPanelForm == null || _controlPanelForm.IsDisposed) return;
// 获取当前选中的模型项
var selectedItems = NavisApplication.ActiveDocument.CurrentSelection.SelectedItems;
int selectedCount = selectedItems.Count;
// 更新指令标签
if (_instructionLabel != null && !_instructionLabel.IsDisposed)
{
_instructionLabel.Text = selectedCount == 0 ? "请在主界面中点击选择模型" : $"已选中 {selectedCount} 个模型";
_instructionLabel.ForeColor = selectedCount > 0 ? System.Drawing.Color.Blue : System.Drawing.Color.Orange;
}
// 更新选中模型标签
if (_selectedModelsLabel != null && !_selectedModelsLabel.IsDisposed)
{
if (selectedCount > 0)
{
string modelNames = string.Join(", ", selectedItems.Take(3).Select(item =>
item.DisplayName.Length > 15 ? item.DisplayName.Substring(0, 15) + "..." : item.DisplayName));
if (selectedCount > 3) modelNames += $" 等{selectedCount}项";
_selectedModelsLabel.Text = $"选中模型: {modelNames}";
_selectedModelsLabel.Visible = true;
}
else
{
_selectedModelsLabel.Visible = false;
}
}
}, "更新选择显示");
}
/// <summary>
/// 刷新界面数据(包括物流模型列表和统计信息)
/// </summary>
private static void RefreshInterfaceData()
{
GlobalExceptionHandler.SafeExecute(() =>
{
// 刷新物流模型列表
if (_logisticsListView != null && !_logisticsListView.IsDisposed)
{
RefreshLogisticsModelListStatic(_logisticsListView);
}
// 更新统计信息
if (_statsLabel != null && !_statsLabel.IsDisposed)
{
UpdateLogisticsStatsStatic(_statsLabel);
}
}, "刷新界面数据");
}
/// <summary>
/// 刷新物流模型列表(静态版本)
/// </summary>
private static void RefreshLogisticsModelListStatic(ListView listView)
{
GlobalExceptionHandler.SafeExecute(() =>
{
listView.Items.Clear();
var document = NavisApplication.ActiveDocument;
if (document?.Models == null) return;
foreach (ModelItem rootItem in document.Models.RootItems)
{
foreach (ModelItem item in rootItem.DescendantsAndSelf)
{
if (CategoryAttributeManager.HasLogisticsAttributes(item))
{
var category = CategoryAttributeManager.GetLogisticsPropertyValue(item, CategoryAttributeManager.LogisticsProperties.TYPE);
var listItem = new ListViewItem(new string[]
{
item.DisplayName.Length > 25 ? item.DisplayName.Substring(0, 25) + "..." : item.DisplayName,
string.IsNullOrEmpty(category) ? "未知" : category
});
listItem.Tag = item; // 保存ModelItem引用
listView.Items.Add(listItem);
}
}
}
LogManager.Info($"物流模型列表已刷新,共 {listView.Items.Count} 项");
}, "刷新物流模型列表");
}
/// <summary>
/// 更新物流统计信息(静态版本)
/// </summary>
private static void UpdateLogisticsStatsStatic(Label statsLabel)
{
GlobalExceptionHandler.SafeExecute(() =>
{
var document = NavisApplication.ActiveDocument;
if (document?.Models == null)
{
statsLabel.Text = "统计: 无活动文档";
return;
}
int totalModels = 0;
int logisticsModels = 0;
// 统计所有模型和物流模型
foreach (ModelItem rootItem in document.Models.RootItems)
{
foreach (ModelItem item in rootItem.DescendantsAndSelf)
{
totalModels++;
if (CategoryAttributeManager.HasLogisticsAttributes(item))
{
logisticsModels++;
}
}
}
statsLabel.Text = $"统计: 总模型 {totalModels} 个,物流模型 {logisticsModels} 个";
}, "更新物流统计");
}
#region PathPlanningManager
/// <summary>
/// 处理路径编辑状态变更事件
/// </summary>
private static void OnPathEditStateChanged(object sender, PathEditState newState)
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info($"[UI同步] ===== 路径编辑状态变更事件触发 =====");
LogManager.Info($"[UI同步] 新状态: {newState}");
LogManager.Info($"[UI同步] 当前线程: {System.Threading.Thread.CurrentThread.ManagedThreadId}");
// 确保在UI线程上执行
if (_controlPanelForm != null && _controlPanelForm.InvokeRequired)
{
LogManager.Info("[UI同步] 需要跨线程调用使用Invoke");
_controlPanelForm.Invoke(new Action(() => OnPathEditStateChanged(sender, newState)));
return;
}
LogManager.Info("[UI同步] 在UI线程上执行状态更新");
// 更新当前路径状态标签
if (_currentPathStatusLabel != null)
{
string stateText;
switch (newState)
{
case PathEditState.Viewing:
stateText = "查看状态";
break;
case PathEditState.Creating:
stateText = "正在新建路径";
break;
case PathEditState.Editing:
stateText = "正在编辑路径";
break;
default:
stateText = "未知状态";
break;
}
LogManager.Info($"[UI同步] 更新状态标签文本: {stateText}");
_currentPathStatusLabel.Text = $"当前状态: {stateText}";
System.Drawing.Color color;
switch (newState)
{
case PathEditState.Viewing:
color = System.Drawing.Color.Gray;
break;
case PathEditState.Creating:
color = System.Drawing.Color.Green;
break;
case PathEditState.Editing:
color = System.Drawing.Color.Blue;
break;
default:
color = System.Drawing.Color.Black;
break;
}
_currentPathStatusLabel.ForeColor = color;
LogManager.Info($"[UI同步] 状态标签颜色已更新: {color}");
}
else
{
LogManager.Warning("[UI同步] _currentPathStatusLabel为null无法更新状态标签");
}
// 更新按钮状态
UpdateButtonStates(newState);
LogManager.Info("[UI同步] ===== 路径编辑状态变更事件处理完成 =====");
}, "处理路径编辑状态变更");
}
/// <summary>
/// 根据编辑状态更新按钮状态
/// </summary>
/// <param name="editState">当前编辑状态</param>
private static void UpdateButtonStates(PathEditState editState)
{
try
{
// 查找完成编辑和取消编辑按钮
if (_controlPanelForm != null)
{
var finishButton = FindButtonByText(_controlPanelForm, "完成编辑");
var cancelButton = FindButtonByText(_controlPanelForm, "取消编辑");
bool isEditable = editState == PathEditState.Creating || editState == PathEditState.Editing;
if (finishButton != null)
{
finishButton.Enabled = isEditable;
}
if (cancelButton != null)
{
cancelButton.Enabled = isEditable;
}
LogManager.Info($"[UI同步] 按钮状态已更新,编辑状态: {editState}, 按钮启用: {isEditable}");
}
}
catch (Exception ex)
{
LogManager.Error($"[UI同步] 更新按钮状态失败: {ex.Message}");
}
}
/// <summary>
/// 根据文本查找按钮控件
/// </summary>
/// <param name="parent">父控件</param>
/// <param name="buttonText">按钮文本</param>
/// <returns>找到的按钮如果没找到返回null</returns>
private static Button FindButtonByText(Control parent, string buttonText)
{
foreach (Control control in parent.Controls)
{
if (control is Button button && button.Text == buttonText)
{
return button;
}
// 递归查找子控件
var foundInChild = FindButtonByText(control, buttonText);
if (foundInChild != null)
{
return foundInChild;
}
}
return null;
}
/// <summary>
/// 处理3D路径点添加事件
/// </summary>
private static void OnPathPointAddedIn3D(object sender, PathPoint pathPoint)
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info($"[UI同步] 3D路径点已添加: {pathPoint?.Name}");
// 更新当前路径点列表
UpdateCurrentPathPointsList();
}, "处理3D路径点添加");
}
/// <summary>
/// 处理3D路径点删除事件
/// </summary>
private static void OnPathPointRemovedFrom3D(object sender, PathPoint pathPoint)
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info($"[UI同步] 3D路径点已删除: {pathPoint?.Name}");
// 更新当前路径点列表
UpdateCurrentPathPointsList();
}, "处理3D路径点删除");
}
/// <summary>
/// 处理路径点列表更新事件
/// </summary>
private static void OnPathPointsListUpdated(object sender, PathRoute updatedRoute)
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info($"[UI同步] 路径点列表已更新: {updatedRoute?.Name ?? ""}");
// 更新当前路径点列表
UpdateCurrentPathPointsList();
// 更新路径列表
UpdatePathList();
}, "处理路径点列表更新");
}
/// <summary>
/// 处理当前路径变更事件
/// </summary>
private static void OnCurrentRouteChanged(object sender, PathRoute newRoute)
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info($"[UI同步] 当前路径已变更: {newRoute?.Name ?? ""}");
// 更新当前路径点列表
UpdateCurrentPathPointsList();
// 更新路径列表
UpdatePathList();
}, "处理当前路径变更");
}
/// <summary>
/// 处理路径管理器状态变更事件
/// </summary>
private static void OnPathManagerStatusChanged(object sender, string status)
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Info($"[UI同步] 路径管理器状态: {status}");
// 可以在这里更新状态栏或其他UI元素
}, "处理路径管理器状态变更");
}
/// <summary>
/// 处理路径管理器错误事件
/// </summary>
private static void OnPathManagerErrorOccurred(object sender, string error)
{
GlobalExceptionHandler.SafeExecute(() =>
{
LogManager.Error($"[UI同步] 路径管理器错误: {error}");
// 显示错误信息
MessageBox.Show($"路径管理器错误: {error}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}, "处理路径管理器错误");
}
/// <summary>
/// 更新当前路径点列表UI
/// </summary>
private static void UpdateCurrentPathPointsList()
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (_currentPathPointsListView == null || _pathPlanningManager == null)
return;
var currentRoute = _pathPlanningManager.CurrentRoute;
_currentPathPointsListView.Items.Clear();
if (currentRoute?.Points != null && currentRoute.Points.Count > 0)
{
for (int i = 0; i < currentRoute.Points.Count; i++)
{
var point = currentRoute.Points[i];
string typeText;
switch (point.Type)
{
case PathPointType.StartPoint:
typeText = "起点";
break;
case PathPointType.EndPoint:
typeText = "终点";
break;
case PathPointType.WayPoint:
typeText = "路径点";
break;
default:
typeText = "未知";
break;
}
// 创建ListViewItem
var item = new ListViewItem((i + 1).ToString()); // 序号
item.SubItems.Add(point.Name); // 名称
item.SubItems.Add(typeText); // 类型
item.SubItems.Add($"({point.Position.X:F1}, {point.Position.Y:F1}, {point.Position.Z:F1})"); // 坐标
_currentPathPointsListView.Items.Add(item);
}
}
else
{
// 可选:添加一个提示项
var placeholder = new ListViewItem("暂无路径点");
placeholder.ForeColor = System.Drawing.Color.Gray;
_currentPathPointsListView.Items.Add(placeholder);
}
LogManager.Info($"[UI同步] 当前路径点列表已更新,共{currentRoute?.Points?.Count ?? 0}个点");
}, "更新当前路径点列表");
}
/// <summary>
/// 更新路径列表UI
/// </summary>
private static void UpdatePathList()
{
GlobalExceptionHandler.SafeExecute(() =>
{
if (_pathListView == null || _pathPlanningManager == null)
return;
_pathListView.Items.Clear();
var routes = _pathPlanningManager.Routes;
if (routes != null && routes.Count > 0)
{
foreach (var route in routes)
{
var item = new ListViewItem(route.Name);
item.SubItems.Add(route.CreatedTime.ToString("MM-dd HH:mm"));
item.SubItems.Add(route.Points?.Count.ToString() ?? "0");
item.Tag = route; // 保存路径对象引用
_pathListView.Items.Add(item);
}
}
LogManager.Info($"[UI同步] 路径列表已更新,共{routes?.Count ?? 0}条路径");
}, "更新路径列表");
}
/// <summary>
/// 显示路径历史记录对话框
/// </summary>
/// <param name="historyEntries">历史记录列表</param>
/// <param name="historyManager">历史记录管理器</param>
private static void ShowPathHistoryDialog(List<PathHistoryEntry> historyEntries, PathHistoryManager historyManager)
{
var historyForm = new Form
{
Text = "路径历史记录",
Size = new Size(600, 400),
StartPosition = FormStartPosition.CenterParent,
FormBorderStyle = FormBorderStyle.FixedDialog,
MaximizeBox = false,
MinimizeBox = false
};
// 创建历史记录列表
var historyListView = new ListView
{
Location = new Point(10, 10),
Size = new Size(565, 300),
View = System.Windows.Forms.View.Details,
FullRowSelect = true,
GridLines = true,
Font = new Font("微软雅黑", 8)
};
// 添加列标题
historyListView.Columns.Add("操作时间", 120);
historyListView.Columns.Add("路径ID", 80);
historyListView.Columns.Add("操作类型", 80);
historyListView.Columns.Add("描述", 260);
// 填充历史记录数据
foreach (var entry in historyEntries)
{
var item = new ListViewItem(new string[]
{
entry.OperationTime.ToString("MM-dd HH:mm:ss"),
entry.RouteId.Substring(0, Math.Min(8, entry.RouteId.Length)) + "...",
GetOperationTypeName(entry.OperationType),
entry.Description
});
item.Tag = entry;
historyListView.Items.Add(item);
}
historyForm.Controls.Add(historyListView);
// 操作按钮
var clearButton = new Button
{
Text = "清空历史",
Location = new Point(10, 320),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
var exportButton = new Button
{
Text = "导出历史",
Location = new Point(100, 320),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8)
};
var closeButton = new Button
{
Text = "关闭",
Location = new Point(495, 320),
Size = new Size(80, 30),
Font = new Font("微软雅黑", 8),
DialogResult = DialogResult.OK
};
// 事件处理
clearButton.Click += (sender, e) => {
var result = MessageBox.Show("确定要清空所有历史记录吗?此操作不可撤销。",
"确认清空", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (result == DialogResult.Yes)
{
try
{
// 清空所有路径的历史记录
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager?.Routes != null)
{
foreach (var route in pathManager.Routes)
{
historyManager.ClearRouteHistory(route.Id);
}
}
historyListView.Items.Clear();
MessageBox.Show("历史记录已清空", "操作完成",
MessageBoxButtons.OK, MessageBoxIcon.Information);
LogManager.Info("用户清空了路径历史记录");
}
catch (Exception ex)
{
MessageBox.Show($"清空历史记录失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
LogManager.Error($"清空历史记录失败: {ex.Message}");
}
}
};
exportButton.Click += (sender, e) => {
try
{
SaveFileDialog saveDialog = new SaveFileDialog
{
Title = "导出历史记录",
Filter = "文本文件 (*.txt)|*.txt|CSV文件 (*.csv)|*.csv",
FilterIndex = 1,
DefaultExt = "txt"
};
if (saveDialog.ShowDialog() == DialogResult.OK)
{
var content = new StringBuilder();
content.AppendLine("路径历史记录导出");
content.AppendLine($"导出时间: {DateTime.Now}");
content.AppendLine($"总记录数: {historyEntries.Count}");
content.AppendLine();
content.AppendLine("操作时间\t路径ID\t操作类型\t描述");
foreach (var entry in historyEntries)
{
content.AppendLine($"{entry.OperationTime:yyyy-MM-dd HH:mm:ss}\t{entry.RouteId}\t{GetOperationTypeName(entry.OperationType)}\t{entry.Description}");
}
File.WriteAllText(saveDialog.FileName, content.ToString(), Encoding.UTF8);
MessageBox.Show($"历史记录已导出到: {saveDialog.FileName}", "导出成功",
MessageBoxButtons.OK, MessageBoxIcon.Information);
LogManager.Info($"历史记录已导出到: {saveDialog.FileName}");
}
}
catch (Exception ex)
{
MessageBox.Show($"导出历史记录失败: {ex.Message}", "错误",
MessageBoxButtons.OK, MessageBoxIcon.Error);
LogManager.Error($"导出历史记录失败: {ex.Message}");
}
};
historyForm.Controls.Add(clearButton);
historyForm.Controls.Add(exportButton);
historyForm.Controls.Add(closeButton);
historyForm.ShowDialog();
}
/// <summary>
/// 获取操作类型的显示名称
/// </summary>
/// <param name="operationType">操作类型</param>
/// <returns>显示名称</returns>
private static string GetOperationTypeName(PathHistoryOperationType operationType)
{
switch (operationType)
{
case PathHistoryOperationType.Created:
return "创建";
case PathHistoryOperationType.Edited:
return "编辑";
case PathHistoryOperationType.PointAdded:
return "添加点";
case PathHistoryOperationType.PointRemoved:
return "删除点";
case PathHistoryOperationType.Optimized:
return "优化";
case PathHistoryOperationType.ManualSave:
return "保存";
default:
return operationType.ToString();
}
}
#endregion
}
}