重新设计了路径可视化机制,重构了系统管理UI

This commit is contained in:
tian 2025-08-20 12:47:12 +08:00
parent 1add8c6410
commit 0e20be9e86
15 changed files with 3757 additions and 780 deletions

View File

@ -193,6 +193,7 @@
<Compile Include="src\UI\WPF\ViewModels\ModelSettingsViewModel.cs" />
<Compile Include="src\UI\WPF\ViewModels\AnimationControlViewModel.cs" />
<Compile Include="src\UI\WPF\ViewModels\PathEditingViewModel.cs" />
<Compile Include="src\UI\WPF\ViewModels\SystemManagementViewModel.cs" />
<!-- UI - WPF Simplified Controls -->
<Compile Include="src\UI\WPF\SimpleLogisticsControlPanel.cs" />

View File

@ -0,0 +1,897 @@
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Threading;
namespace NavisworksTransport.UI.WPF.ViewModels
{
/// <summary>
/// 系统管理ViewModel - 参照PathEditingViewModel的设计模式
/// 专门负责系统管理相关功能,包括:日志管理、设置管理、性能监控、版本控制、配置管理等
/// </summary>
public class SystemManagementViewModel : ViewModelBase
{
#region
// 依赖注入的核心服务
private readonly UIStateManager _uiStateManager;
// 系统管理相关的管理器实例(通过依赖注入)
private ISystemLogManager _logManager;
private ISystemConfigManager _configManager;
private IPerformanceMonitor _performanceMonitor;
private IModelSplitterManager _modelSplitterManager;
// 日志管理相关字段
private ObservableCollection<string> _logLevels;
private string _selectedLogLevel = "Info";
private string _logStatus = "日志系统正常";
private int _logEntryCount = 0;
private string _logFilePath = "未设置";
// 系统设置相关字段
private bool _isAutoSaveEnabled = true;
private bool _isDebugModeEnabled = false;
private string _settingsStatus = "设置已加载";
private int _autoSaveInterval = 300; // 秒
private string _workingDirectory = "";
// 版本和系统信息相关字段
private string _pluginVersion = "v1.0";
private string _navisworksVersion = "2026";
private string _systemStatus = "正常";
private string _systemStatusColor = "Green";
private string _lastUpdateCheck = "未检查";
// 性能监控相关字段
private string _memoryUsage = "0 MB";
private string _runningTime = "00:00:00";
private string _performanceInfo = "性能监控就绪";
private double _cpuUsage = 0.0;
private int _threadsCount = 0;
private DispatcherTimer _performanceTimer;
// 模型分割器相关字段
private string _modelSplitterStatus = "就绪";
private bool _canRunModelSplitter = true;
private string _lastSplitResult = "未执行";
// 配置管理相关字段
private string _currentConfigProfile = "默认配置";
private ObservableCollection<string> _availableProfiles;
private bool _hasUnsavedChanges = false;
#endregion
#region
#region
/// <summary>
/// 可用日志级别集合
/// </summary>
public ObservableCollection<string> LogLevels
{
get => _logLevels;
set => SetProperty(ref _logLevels, value);
}
/// <summary>
/// 选中的日志级别
/// </summary>
public string SelectedLogLevel
{
get => _selectedLogLevel;
set
{
if (SetProperty(ref _selectedLogLevel, value))
{
OnLogLevelChanged();
}
}
}
/// <summary>
/// 日志系统状态
/// </summary>
public string LogStatus
{
get => _logStatus;
set => SetProperty(ref _logStatus, value);
}
/// <summary>
/// 日志条目数量
/// </summary>
public int LogEntryCount
{
get => _logEntryCount;
set => SetProperty(ref _logEntryCount, value);
}
/// <summary>
/// 日志文件路径
/// </summary>
public string LogFilePath
{
get => _logFilePath;
set => SetProperty(ref _logFilePath, value);
}
#endregion
#region
/// <summary>
/// 是否启用自动保存
/// </summary>
public bool IsAutoSaveEnabled
{
get => _isAutoSaveEnabled;
set
{
if (SetProperty(ref _isAutoSaveEnabled, value))
{
OnAutoSaveSettingChanged();
}
}
}
/// <summary>
/// 是否启用调试模式
/// </summary>
public bool IsDebugModeEnabled
{
get => _isDebugModeEnabled;
set
{
if (SetProperty(ref _isDebugModeEnabled, value))
{
OnDebugModeChanged();
}
}
}
/// <summary>
/// 设置状态
/// </summary>
public string SettingsStatus
{
get => _settingsStatus;
set => SetProperty(ref _settingsStatus, value);
}
/// <summary>
/// 自动保存间隔(秒)
/// </summary>
public int AutoSaveInterval
{
get => _autoSaveInterval;
set
{
if (SetProperty(ref _autoSaveInterval, value))
{
OnAutoSaveIntervalChanged();
}
}
}
/// <summary>
/// 工作目录
/// </summary>
public string WorkingDirectory
{
get => _workingDirectory;
set => SetProperty(ref _workingDirectory, value);
}
#endregion
#region
/// <summary>
/// 插件版本
/// </summary>
public string PluginVersion
{
get => _pluginVersion;
set => SetProperty(ref _pluginVersion, value);
}
/// <summary>
/// Navisworks版本
/// </summary>
public string NavisworksVersion
{
get => _navisworksVersion;
set => SetProperty(ref _navisworksVersion, value);
}
/// <summary>
/// 系统状态
/// </summary>
public string SystemStatus
{
get => _systemStatus;
set => SetProperty(ref _systemStatus, value);
}
/// <summary>
/// 系统状态颜色
/// </summary>
public string SystemStatusColor
{
get => _systemStatusColor;
set => SetProperty(ref _systemStatusColor, value);
}
/// <summary>
/// 最后更新检查时间
/// </summary>
public string LastUpdateCheck
{
get => _lastUpdateCheck;
set => SetProperty(ref _lastUpdateCheck, value);
}
#endregion
#region
/// <summary>
/// 内存使用情况
/// </summary>
public string MemoryUsage
{
get => _memoryUsage;
set => SetProperty(ref _memoryUsage, value);
}
/// <summary>
/// 运行时间
/// </summary>
public string RunningTime
{
get => _runningTime;
set => SetProperty(ref _runningTime, value);
}
/// <summary>
/// 性能信息
/// </summary>
public string PerformanceInfo
{
get => _performanceInfo;
set => SetProperty(ref _performanceInfo, value);
}
/// <summary>
/// CPU使用率
/// </summary>
public double CpuUsage
{
get => _cpuUsage;
set => SetProperty(ref _cpuUsage, value);
}
/// <summary>
/// 线程数量
/// </summary>
public int ThreadsCount
{
get => _threadsCount;
set => SetProperty(ref _threadsCount, value);
}
#endregion
#region
/// <summary>
/// 模型分层拆分状态
/// </summary>
public string ModelSplitterStatus
{
get => _modelSplitterStatus;
set => SetProperty(ref _modelSplitterStatus, value);
}
/// <summary>
/// 是否可以运行模型分割器
/// </summary>
public bool CanRunModelSplitter
{
get => _canRunModelSplitter;
set => SetProperty(ref _canRunModelSplitter, value);
}
/// <summary>
/// 最后分割结果
/// </summary>
public string LastSplitResult
{
get => _lastSplitResult;
set => SetProperty(ref _lastSplitResult, value);
}
#endregion
#region
/// <summary>
/// 当前配置档案
/// </summary>
public string CurrentConfigProfile
{
get => _currentConfigProfile;
set => SetProperty(ref _currentConfigProfile, value);
}
/// <summary>
/// 可用配置档案
/// </summary>
public ObservableCollection<string> AvailableProfiles
{
get => _availableProfiles;
set => SetProperty(ref _availableProfiles, value);
}
/// <summary>
/// 是否有未保存的更改
/// </summary>
public bool HasUnsavedChanges
{
get => _hasUnsavedChanges;
set => SetProperty(ref _hasUnsavedChanges, value);
}
#endregion
#endregion
#region
// 日志管理命令
public ICommand ViewLogCommand { get; private set; }
public ICommand ClearLogCommand { get; private set; }
public ICommand ExportLogCommand { get; private set; }
public ICommand RefreshLogStatusCommand { get; private set; }
// 设置管理命令
public ICommand OpenSettingsCommand { get; private set; }
public ICommand ResetSettingsCommand { get; private set; }
public ICommand SaveSettingsCommand { get; private set; }
public ICommand LoadSettingsCommand { get; private set; }
// 配置管理命令
public ICommand ImportConfigCommand { get; private set; }
public ICommand ExportConfigCommand { get; private set; }
public ICommand CreateProfileCommand { get; private set; }
public ICommand DeleteProfileCommand { get; private set; }
public ICommand SwitchProfileCommand { get; private set; }
// 系统管理命令
public ICommand CheckUpdateCommand { get; private set; }
public ICommand RestartSystemCommand { get; private set; }
public ICommand SystemDiagnosticsCommand { get; private set; }
// 性能管理命令
public ICommand GeneratePerformanceReportCommand { get; private set; }
public ICommand StartPerformanceMonitoringCommand { get; private set; }
public ICommand StopPerformanceMonitoringCommand { get; private set; }
public ICommand ClearPerformanceDataCommand { get; private set; }
// 模型分割器命令
public ICommand RunModelSplitterCommand { get; private set; }
public ICommand ConfigureModelSplitterCommand { get; private set; }
#endregion
#region
/// <summary>
/// 构造函数 - 参照PathEditingViewModel的设计模式
/// </summary>
/// <param name="logManager">日志管理器(可选,用于依赖注入)</param>
/// <param name="configManager">配置管理器(可选,用于依赖注入)</param>
/// <param name="performanceMonitor">性能监控器(可选,用于依赖注入)</param>
/// <param name="modelSplitterManager">模型分割器管理器(可选,用于依赖注入)</param>
public SystemManagementViewModel(
ISystemLogManager logManager = null,
ISystemConfigManager configManager = null,
IPerformanceMonitor performanceMonitor = null,
IModelSplitterManager modelSplitterManager = null) : base()
{
try
{
// 获取UI状态管理器
_uiStateManager = UIStateManager.Instance;
if (_uiStateManager == null)
{
throw new InvalidOperationException("UIStateManager初始化失败");
}
// 设置依赖如果为null则使用默认实现
_logManager = logManager ?? CreateDefaultLogManager();
_configManager = configManager ?? CreateDefaultConfigManager();
_performanceMonitor = performanceMonitor ?? CreateDefaultPerformanceMonitor();
_modelSplitterManager = modelSplitterManager ?? CreateDefaultModelSplitterManager();
// 初始化集合
LogLevels = new ThreadSafeObservableCollection<string>();
AvailableProfiles = new ThreadSafeObservableCollection<string>();
// 初始化命令
InitializeCommands();
// 初始化系统管理设置(异步)
InitializeSystemManagementAsync();
LogManager.Info("SystemManagementViewModel构造函数执行完成");
}
catch (Exception ex)
{
LogManager.Error($"SystemManagementViewModel构造函数异常: {ex.Message}", ex);
SystemStatus = "初始化失败,请检查日志";
SystemStatusColor = "Red";
throw;
}
}
#endregion
#region
/// <summary>
/// 初始化命令
/// </summary>
private void InitializeCommands()
{
// 日志管理命令
ViewLogCommand = new RelayCommand(async () => await ExecuteViewLogAsync());
ClearLogCommand = new RelayCommand(async () => await ExecuteClearLogAsync());
ExportLogCommand = new RelayCommand(async () => await ExecuteExportLogAsync());
RefreshLogStatusCommand = new RelayCommand(async () => await ExecuteRefreshLogStatusAsync());
// 设置管理命令
OpenSettingsCommand = new RelayCommand(async () => await ExecuteOpenSettingsAsync());
ResetSettingsCommand = new RelayCommand(async () => await ExecuteResetSettingsAsync());
SaveSettingsCommand = new RelayCommand(async () => await ExecuteSaveSettingsAsync());
LoadSettingsCommand = new RelayCommand(async () => await ExecuteLoadSettingsAsync());
// 配置管理命令
ImportConfigCommand = new RelayCommand(async () => await ExecuteImportConfigAsync());
ExportConfigCommand = new RelayCommand(async () => await ExecuteExportConfigAsync());
CreateProfileCommand = new RelayCommand(async () => await ExecuteCreateProfileAsync());
DeleteProfileCommand = new RelayCommand(async () => await ExecuteDeleteProfileAsync());
SwitchProfileCommand = new RelayCommand<string>(async (profile) => await ExecuteSwitchProfileAsync(profile));
// 系统管理命令
CheckUpdateCommand = new RelayCommand(async () => await ExecuteCheckUpdateAsync());
RestartSystemCommand = new RelayCommand(async () => await ExecuteRestartSystemAsync());
SystemDiagnosticsCommand = new RelayCommand(async () => await ExecuteSystemDiagnosticsAsync());
// 性能管理命令
GeneratePerformanceReportCommand = new RelayCommand(async () => await ExecuteGeneratePerformanceReportAsync());
StartPerformanceMonitoringCommand = new RelayCommand(async () => await ExecuteStartPerformanceMonitoringAsync());
StopPerformanceMonitoringCommand = new RelayCommand(async () => await ExecuteStopPerformanceMonitoringAsync());
ClearPerformanceDataCommand = new RelayCommand(async () => await ExecuteClearPerformanceDataAsync());
// 模型分割器命令
RunModelSplitterCommand = new RelayCommand(async () => await ExecuteRunModelSplitterAsync(), () => CanRunModelSplitter);
ConfigureModelSplitterCommand = new RelayCommand(async () => await ExecuteConfigureModelSplitterAsync());
}
/// <summary>
/// 异步初始化系统管理设置
/// </summary>
private async void InitializeSystemManagementAsync()
{
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 初始化日志级别
LogLevels.Clear();
var logLevels = new[] { "Debug", "Info", "Warning", "Error" };
foreach (var level in logLevels)
{
LogLevels.Add(level);
}
SelectedLogLevel = "Info";
// 初始化配置档案
AvailableProfiles.Clear();
var profiles = new[] { "默认配置", "开发配置", "生产配置", "测试配置" };
foreach (var profile in profiles)
{
AvailableProfiles.Add(profile);
}
CurrentConfigProfile = "默认配置";
// 初始化系统信息
PluginVersion = GetPluginVersion();
NavisworksVersion = GetNavisworksVersion();
SystemStatus = "正常";
SystemStatusColor = "Green";
WorkingDirectory = GetWorkingDirectory();
LogFilePath = GetLogFilePath();
});
// 启动性能监控
await StartPerformanceMonitoring();
LogManager.Info("系统管理设置初始化完成");
}, "初始化系统管理设置");
}
#endregion
#region
// 这里只展示架构框架,具体实现方法将在后续详细说明
#region
private async Task ExecuteViewLogAsync()
{
await SafeExecuteAsync(async () =>
{
// TODO: 实现日志查看功能
await _logManager.OpenLogViewerAsync();
LogStatus = "日志查看器已打开";
}, "查看日志");
}
private async Task ExecuteClearLogAsync()
{
await SafeExecuteAsync(async () =>
{
// TODO: 实现日志清空功能
await _logManager.ClearLogsAsync();
LogEntryCount = 0;
LogStatus = "日志已清空";
}, "清空日志");
}
private async Task ExecuteExportLogAsync()
{
await SafeExecuteAsync(async () =>
{
// TODO: 实现日志导出功能
var exportPath = await _logManager.ExportLogsAsync();
LogStatus = $"日志已导出到: {exportPath}";
}, "导出日志");
}
private async Task ExecuteRefreshLogStatusAsync()
{
await SafeExecuteAsync(async () =>
{
// TODO: 实现日志状态刷新功能
var status = await _logManager.GetLogStatusAsync();
LogStatus = status.Message;
LogEntryCount = status.EntryCount;
LogFilePath = status.FilePath;
}, "刷新日志状态");
}
#endregion
// 其他命令实现方法...
// (这里省略具体实现,在实际代码中会完整实现)
#endregion
#region
/// <summary>
/// 处理日志级别改变事件
/// </summary>
private void OnLogLevelChanged()
{
SafeExecute(() =>
{
_logManager?.SetLogLevel(SelectedLogLevel);
LogStatus = $"日志级别已设置为: {SelectedLogLevel}";
}, "设置日志级别");
}
/// <summary>
/// 处理自动保存设置改变事件
/// </summary>
private void OnAutoSaveSettingChanged()
{
SafeExecute(() =>
{
_configManager?.SetAutoSaveEnabled(IsAutoSaveEnabled);
SettingsStatus = $"自动保存: {(IsAutoSaveEnabled ? "" : "")}";
HasUnsavedChanges = true;
}, "设置自动保存");
}
/// <summary>
/// 处理调试模式改变事件
/// </summary>
private void OnDebugModeChanged()
{
SafeExecute(() =>
{
_configManager?.SetDebugMode(IsDebugModeEnabled);
SettingsStatus = $"调试模式: {(IsDebugModeEnabled ? "" : "")}";
HasUnsavedChanges = true;
}, "设置调试模式");
}
/// <summary>
/// 处理自动保存间隔改变事件
/// </summary>
private void OnAutoSaveIntervalChanged()
{
SafeExecute(() =>
{
_configManager?.SetAutoSaveInterval(AutoSaveInterval);
SettingsStatus = $"自动保存间隔: {AutoSaveInterval}秒";
HasUnsavedChanges = true;
}, "设置自动保存间隔");
}
#endregion
#region
/// <summary>
/// 安全执行异步操作
/// </summary>
private async Task SafeExecuteAsync(Func<Task> action, string operationName = "未知操作")
{
try
{
await action();
}
catch (Exception ex)
{
LogManager.Error($"{operationName}发生异常: {ex.Message}", ex);
SystemStatus = $"{operationName}失败: {ex.Message}";
SystemStatusColor = "Red";
}
}
/// <summary>
/// 安全执行同步操作
/// </summary>
private void SafeExecute(Action action, string operationName = "未知操作")
{
try
{
action();
}
catch (Exception ex)
{
LogManager.Error($"{operationName}发生异常: {ex.Message}", ex);
SystemStatus = $"{operationName}失败: {ex.Message}";
SystemStatusColor = "Red";
}
}
#endregion
#region
/// <summary>
/// 启动性能监控
/// </summary>
private async Task StartPerformanceMonitoring()
{
await SafeExecuteAsync(async () =>
{
var startTime = DateTime.Now;
// 使用定时器更新性能信息
_performanceTimer = new DispatcherTimer();
_performanceTimer.Interval = TimeSpan.FromSeconds(5);
_performanceTimer.Tick += async (s, e) =>
{
try
{
await UpdatePerformanceInfo(startTime);
}
catch (Exception ex)
{
LogManager.Error($"性能监控更新失败: {ex.Message}");
}
};
_performanceTimer.Start();
PerformanceInfo = "性能监控已启动";
}, "启动性能监控");
}
/// <summary>
/// 更新性能信息
/// </summary>
private async Task UpdatePerformanceInfo(DateTime startTime)
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 更新内存使用
var process = Process.GetCurrentProcess();
var memoryMB = process.WorkingSet64 / (1024 * 1024);
MemoryUsage = $"{memoryMB} MB";
// 更新运行时间
var runTime = DateTime.Now - startTime;
RunningTime = $"{runTime.Hours:D2}:{runTime.Minutes:D2}:{runTime.Seconds:D2}";
// 更新线程数
ThreadsCount = process.Threads.Count;
// 更新性能信息
PerformanceInfo = $"CPU: 正常, 内存: {memoryMB}MB, 线程: {ThreadsCount}, 运行时间: {RunningTime}";
});
}
#endregion
#region
private ISystemLogManager CreateDefaultLogManager()
{
// TODO: 创建默认日志管理器实现
return new DefaultSystemLogManager();
}
private ISystemConfigManager CreateDefaultConfigManager()
{
// TODO: 创建默认配置管理器实现
return new DefaultSystemConfigManager();
}
private IPerformanceMonitor CreateDefaultPerformanceMonitor()
{
// TODO: 创建默认性能监控器实现
return new DefaultPerformanceMonitor();
}
private IModelSplitterManager CreateDefaultModelSplitterManager()
{
// TODO: 创建默认模型分割器管理器实现
return new DefaultModelSplitterManager();
}
#endregion
#region
private string GetPluginVersion()
{
// TODO: 从程序集获取插件版本
return "v1.0";
}
private string GetNavisworksVersion()
{
// TODO: 从Navisworks API获取版本信息
return "2026";
}
private string GetWorkingDirectory()
{
// TODO: 获取当前工作目录
return Environment.CurrentDirectory;
}
private string GetLogFilePath()
{
// TODO: 获取日志文件路径
return Path.Combine(GetWorkingDirectory(), "Logs", "NavisworksTransport.log");
}
#endregion
#region
/// <summary>
/// 清理资源
/// </summary>
public void Cleanup()
{
try
{
LogManager.Info("开始清理SystemManagementViewModel资源");
// 停止性能监控定时器
if (_performanceTimer != null)
{
_performanceTimer.Stop();
_performanceTimer = null;
}
// 清理管理器资源
_logManager?.Dispose();
_configManager?.Dispose();
_performanceMonitor?.Dispose();
_modelSplitterManager?.Dispose();
LogManager.Info("SystemManagementViewModel资源清理完成");
}
catch (Exception ex)
{
LogManager.Error($"SystemManagementViewModel清理失败: {ex.Message}");
}
}
#endregion
}
}
// 接口定义(这些接口将在单独的文件中定义)
/// <summary>
/// 系统日志管理器接口
/// </summary>
public interface ISystemLogManager : IDisposable
{
Task OpenLogViewerAsync();
Task ClearLogsAsync();
Task<string> ExportLogsAsync();
Task<LogStatus> GetLogStatusAsync();
void SetLogLevel(string level);
}
/// <summary>
/// 系统配置管理器接口
/// </summary>
public interface ISystemConfigManager : IDisposable
{
void SetAutoSaveEnabled(bool enabled);
void SetDebugMode(bool enabled);
void SetAutoSaveInterval(int seconds);
Task SaveConfigAsync();
Task LoadConfigAsync();
}
/// <summary>
/// 性能监控器接口
/// </summary>
public interface IPerformanceMonitor : IDisposable
{
Task<PerformanceData> GetCurrentPerformanceAsync();
Task StartMonitoringAsync();
Task StopMonitoringAsync();
}
/// <summary>
/// 模型分割器管理器接口
/// </summary>
public interface IModelSplitterManager : IDisposable
{
Task<bool> RunModelSplitterAsync();
Task ConfigureAsync();
bool CanRun { get; }
}
/// <summary>
/// 日志状态数据结构
/// </summary>
public class LogStatus
{
public string Message { get; set; }
public int EntryCount { get; set; }
public string FilePath { get; set; }
}
/// <summary>
/// 性能数据结构
/// </summary>
public class PerformanceData
{
public double CpuUsage { get; set; }
public long MemoryUsage { get; set; }
public int ThreadCount { get; set; }
public TimeSpan RunningTime { get; set; }
}

View File

@ -0,0 +1,457 @@
# SystemManagementViewModel 集成方案
## 1. 与LogisticsControlViewModel的解耦策略
### 1.1 依赖关系处理
**原始依赖关系问题:**
- LogisticsControlViewModel 直接包含所有系统管理代码
- UI更新、状态管理、业务逻辑混合在一起
- 违反单一职责原则
**解耦方案:**
```csharp
// 在LogisticsControlViewModel中
public class LogisticsControlViewModel : ViewModelBase
{
// 移除所有系统管理相关的字段和属性
// private string _modelSplitterStatus; // 删除
// private ObservableCollection<string> _logLevels; // 删除
// ... 其他系统管理相关代码
// 添加SystemManagementViewModel的引用
private SystemManagementViewModel _systemManagementViewModel;
public SystemManagementViewModel SystemManagement
{
get => _systemManagementViewModel;
private set => SetProperty(ref _systemManagementViewModel, value);
}
public LogisticsControlViewModel() : base()
{
try
{
// 原有初始化代码...
// 初始化系统管理ViewModel
SystemManagement = new SystemManagementViewModel();
// 订阅系统管理事件(如果需要)
SubscribeToSystemManagementEvents();
}
catch (Exception ex)
{
// 错误处理
}
}
// 移除所有系统管理相关的方法
// private async Task InitializeSystemManagementSettingsAsync() // 删除
// private void ExecuteClearLog() // 删除
// private void ExecuteExportLog() // 删除
// ... 其他系统管理方法
}
```
### 1.2 事件通信机制
```csharp
// 定义系统管理事件接口
public interface ISystemManagementEvents
{
event EventHandler<SystemStatusChangedEventArgs> SystemStatusChanged;
event EventHandler<PerformanceAlertEventArgs> PerformanceAlert;
event EventHandler<ConfigurationChangedEventArgs> ConfigurationChanged;
}
// 在SystemManagementViewModel中实现事件发布
public class SystemManagementViewModel : ViewModelBase, ISystemManagementEvents
{
public event EventHandler<SystemStatusChangedEventArgs> SystemStatusChanged;
public event EventHandler<PerformanceAlertEventArgs> PerformanceAlert;
public event EventHandler<ConfigurationChangedEventArgs> ConfigurationChanged;
// 触发系统状态变更事件
private void OnSystemStatusChanged(string newStatus, string color)
{
SystemStatusChanged?.Invoke(this, new SystemStatusChangedEventArgs
{
Status = newStatus,
StatusColor = color,
Timestamp = DateTime.Now
});
}
// 触发性能警告事件
private void OnPerformanceAlert(PerformanceAlertType alertType, string message)
{
PerformanceAlert?.Invoke(this, new PerformanceAlertEventArgs
{
AlertType = alertType,
Message = message,
Timestamp = DateTime.Now
});
}
}
// 在LogisticsControlViewModel中订阅事件
private void SubscribeToSystemManagementEvents()
{
if (SystemManagement != null)
{
SystemManagement.SystemStatusChanged += OnSystemStatusChanged;
SystemManagement.PerformanceAlert += OnPerformanceAlert;
SystemManagement.ConfigurationChanged += OnConfigurationChanged;
}
}
private void OnSystemStatusChanged(object sender, SystemStatusChangedEventArgs e)
{
// 处理系统状态变更如果主ViewModel需要知道
// 例如:更新主界面的状态指示器
StatusText = $"系统状态: {e.Status}";
}
```
## 2. UI集成策略
### 2.1 XAML绑定方案
```xml
<!-- 原始的SystemManagementView.xaml -->
<!-- 通过DataContext绑定到LogisticsControlViewModel.SystemManagement -->
<UserControl x:Class="NavisworksTransport.UI.WPF.Views.SystemManagementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- 原有的UI控件绑定路径需要调整 -->
<!-- 原来: -->
<!-- <ComboBox ItemsSource="{Binding LogLevels}" SelectedItem="{Binding SelectedLogLevel}" /> -->
<!-- 现在: -->
<!-- 通过父级LogisticsControlViewModel的SystemManagement属性访问 -->
<ComboBox ItemsSource="{Binding SystemManagement.LogLevels}"
SelectedItem="{Binding SystemManagement.SelectedLogLevel}" />
<Button Content="查看日志" Command="{Binding SystemManagement.ViewLogCommand}" />
<Button Content="清空日志" Command="{Binding SystemManagement.ClearLogCommand}" />
<Button Content="导出日志" Command="{Binding SystemManagement.ExportLogCommand}" />
<!-- 性能监控控件 -->
<TextBlock Text="{Binding SystemManagement.MemoryUsage}" />
<TextBlock Text="{Binding SystemManagement.RunningTime}" />
<TextBlock Text="{Binding SystemManagement.PerformanceInfo}" />
<!-- 系统状态控件 -->
<TextBlock Text="{Binding SystemManagement.SystemStatus}"
Foreground="{Binding SystemManagement.SystemStatusColor}" />
</UserControl>
```
### 2.2 ViewModelLocator调整
```csharp
// 在ViewModelLocator中注册SystemManagementViewModel
public class ViewModelLocator
{
public LogisticsControlViewModel LogisticsControl => ServiceLocator.Current.GetInstance<LogisticsControlViewModel>();
// 可以选择直接注册SystemManagementViewModel
public SystemManagementViewModel SystemManagement => ServiceLocator.Current.GetInstance<SystemManagementViewModel>();
static ViewModelLocator()
{
// 注册服务
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
// 注册SystemManagementViewModel及其依赖
SimpleIoc.Default.Register<ISystemLogManager, DefaultSystemLogManager>();
SimpleIoc.Default.Register<ISystemConfigManager, DefaultSystemConfigManager>();
SimpleIoc.Default.Register<IPerformanceMonitor, DefaultPerformanceMonitor>();
SimpleIoc.Default.Register<IModelSplitterManager, DefaultModelSplitterManager>();
SimpleIoc.Default.Register<SystemManagementViewModel>();
SimpleIoc.Default.Register<LogisticsControlViewModel>();
}
}
```
## 3. 初始化和生命周期管理
### 3.1 初始化顺序
```csharp
public class LogisticsControlViewModel : ViewModelBase
{
private async void InitializeViewModelAsync()
{
await SafeExecuteAsync(async () =>
{
// 1. 先初始化核心组件
await UpdateInstructionTextAsync();
await UpdateSelectionDisplayAsync();
await InitializeCategoriesAsync();
// 2. 初始化系统管理ViewModel
await InitializeSystemManagementAsync();
// 3. 最后更新UI状态
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
StatusText = "插件已就绪";
AnimationStatus = "动画状态: 就绪";
AnimationProgress = 0;
WidthLimit = 3.0;
});
// 4. 初始化动画设置
await InitializeAnimationSettingsAsync();
LogManager.Info("LogisticsControlViewModel 初始化完成");
}, "初始化ViewModel");
}
private async Task InitializeSystemManagementAsync()
{
await SafeExecuteAsync(async () =>
{
// 创建SystemManagementViewModel实例
SystemManagement = new SystemManagementViewModel(
logManager: ServiceProvider.GetService<ISystemLogManager>(),
configManager: ServiceProvider.GetService<ISystemConfigManager>(),
performanceMonitor: ServiceProvider.GetService<IPerformanceMonitor>(),
modelSplitterManager: ServiceProvider.GetService<IModelSplitterManager>()
);
// 订阅系统管理事件
SubscribeToSystemManagementEvents();
LogManager.Info("系统管理ViewModel初始化完成");
}, "初始化系统管理");
}
}
```
### 3.2 清理机制
```csharp
public class LogisticsControlViewModel : ViewModelBase
{
// 添加清理方法
public void Cleanup()
{
try
{
LogManager.Info("开始清理LogisticsControlViewModel资源");
// 清理系统管理ViewModel
if (SystemManagement != null)
{
UnsubscribeFromSystemManagementEvents();
SystemManagement.Cleanup();
SystemManagement = null;
}
// 原有的清理代码...
LogManager.Info("LogisticsControlViewModel资源清理完成");
}
catch (Exception ex)
{
LogManager.Error($"LogisticsControlViewModel清理失败: {ex.Message}");
}
}
private void UnsubscribeFromSystemManagementEvents()
{
if (SystemManagement != null)
{
SystemManagement.SystemStatusChanged -= OnSystemStatusChanged;
SystemManagement.PerformanceAlert -= OnPerformanceAlert;
SystemManagement.ConfigurationChanged -= OnConfigurationChanged;
}
}
}
```
## 4. 命令重定向机制
### 4.1 保持向后兼容性
```csharp
public class LogisticsControlViewModel : ViewModelBase
{
// 保持原有命令接口但重定向到SystemManagementViewModel
public ICommand ViewLogCommand => SystemManagement?.ViewLogCommand;
public ICommand ClearLogCommand => SystemManagement?.ClearLogCommand;
public ICommand ExportLogCommand => SystemManagement?.ExportLogCommand;
public ICommand OpenSettingsCommand => SystemManagement?.OpenSettingsCommand;
public ICommand ResetSettingsCommand => SystemManagement?.ResetSettingsCommand;
public ICommand ImportConfigCommand => SystemManagement?.ImportConfigCommand;
public ICommand CheckUpdateCommand => SystemManagement?.CheckUpdateCommand;
public ICommand GeneratePerformanceReportCommand => SystemManagement?.GeneratePerformanceReportCommand;
// 或者使用代理模式
private void InitializeCommandProxies()
{
ViewLogCommand = new RelayCommand(async () =>
{
if (SystemManagement != null)
await SystemManagement.ViewLogCommand.ExecuteAsync(null);
});
ClearLogCommand = new RelayCommand(async () =>
{
if (SystemManagement != null)
await SystemManagement.ClearLogCommand.ExecuteAsync(null);
});
// ... 其他命令代理
}
}
```
## 5. 测试策略
### 5.1 单元测试
```csharp
[TestFixture]
public class SystemManagementViewModelTests
{
private SystemManagementViewModel _viewModel;
private Mock<ISystemLogManager> _mockLogManager;
private Mock<ISystemConfigManager> _mockConfigManager;
[SetUp]
public void Setup()
{
_mockLogManager = new Mock<ISystemLogManager>();
_mockConfigManager = new Mock<ISystemConfigManager>();
_viewModel = new SystemManagementViewModel(
_mockLogManager.Object,
_mockConfigManager.Object
);
}
[Test]
public async Task ExecuteViewLogAsync_ShouldCallLogManager()
{
// Arrange
_mockLogManager.Setup(x => x.OpenLogViewerAsync()).Returns(Task.CompletedTask);
// Act
await _viewModel.ViewLogCommand.ExecuteAsync(null);
// Assert
_mockLogManager.Verify(x => x.OpenLogViewerAsync(), Times.Once);
Assert.AreEqual("日志查看器已打开", _viewModel.LogStatus);
}
}
```
### 5.2 集成测试
```csharp
[TestFixture]
public class SystemManagementIntegrationTests
{
[Test]
public void LogisticsControlViewModel_ShouldInitializeSystemManagement()
{
// Arrange & Act
var logisticsVM = new LogisticsControlViewModel();
// Assert
Assert.IsNotNull(logisticsVM.SystemManagement);
Assert.IsInstanceOf<SystemManagementViewModel>(logisticsVM.SystemManagement);
}
[Test]
public void SystemManagementEvents_ShouldPropagateToMainViewModel()
{
// Arrange
var logisticsVM = new LogisticsControlViewModel();
var systemManagementVM = logisticsVM.SystemManagement;
string receivedStatus = null;
logisticsVM.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(LogisticsControlViewModel.StatusText))
receivedStatus = logisticsVM.StatusText;
};
// Act
systemManagementVM.SystemStatus = "测试状态";
// 触发SystemStatusChanged事件
// Assert
Assert.IsTrue(receivedStatus?.Contains("测试状态"));
}
}
```
## 6. 迁移计划
### 6.1 分阶段迁移
**阶段1创建基础架构**
1. 创建SystemManagementViewModel类
2. 定义所需接口
3. 创建默认实现类
4. 设置依赖注入
**阶段2迁移核心功能**
1. 迁移日志管理功能
2. 迁移设置管理功能
3. 迁移性能监控功能
4. 测试基本功能
**阶段3集成和优化**
1. 集成到LogisticsControlViewModel
2. 调整UI绑定
3. 实现事件通信
4. 性能优化
**阶段4测试和部署**
1. 全面测试
2. 修复问题
3. 文档更新
4. 部署验证
### 6.2 兼容性保证
```csharp
// 在迁移期间,保持旧接口可用
public class LogisticsControlViewModel : ViewModelBase
{
// 新的系统管理ViewModel
private SystemManagementViewModel _systemManagement;
// 保持旧属性兼容性(标记为过时)
[Obsolete("请使用SystemManagement.LogLevels", false)]
public ObservableCollection<string> LogLevels => SystemManagement?.LogLevels;
[Obsolete("请使用SystemManagement.SelectedLogLevel", false)]
public string SelectedLogLevel
{
get => SystemManagement?.SelectedLogLevel;
set { if (SystemManagement != null) SystemManagement.SelectedLogLevel = value; }
}
// 保持旧命令兼容性
[Obsolete("请使用SystemManagement.ViewLogCommand", false)]
public ICommand ViewLogCommand => SystemManagement?.ViewLogCommand;
}
```
这个解耦方案确保了:
1. **清晰的职责分离**:系统管理功能完全独立
2. **向后兼容性**现有UI和代码不会立即失效
3. **渐进式迁移**:可以分步骤进行迁移
4. **良好的测试性**:每个组件都可以独立测试
5. **事件驱动通信**:组件间通过事件解耦

View File

@ -0,0 +1,744 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Windows;
namespace NavisworksTransport.Core.SystemManagement
{
#region
/// <summary>
/// 系统状态变更事件参数
/// </summary>
public class SystemStatusChangedEventArgs : EventArgs
{
public string Status { get; set; }
public string StatusColor { get; set; }
public DateTime Timestamp { get; set; }
public string Details { get; set; }
}
/// <summary>
/// 性能警告事件参数
/// </summary>
public class PerformanceAlertEventArgs : EventArgs
{
public PerformanceAlertType AlertType { get; set; }
public string Message { get; set; }
public DateTime Timestamp { get; set; }
public double Value { get; set; }
public double Threshold { get; set; }
}
/// <summary>
/// 配置变更事件参数
/// </summary>
public class ConfigurationChangedEventArgs : EventArgs
{
public string ConfigKey { get; set; }
public object OldValue { get; set; }
public object NewValue { get; set; }
public string ProfileName { get; set; }
public DateTime Timestamp { get; set; }
}
/// <summary>
/// 性能警告类型枚举
/// </summary>
public enum PerformanceAlertType
{
MemoryHigh,
CpuHigh,
ThreadCountHigh,
ResponseTimeLow
}
#endregion
#region
/// <summary>
/// 日志状态数据模型
/// </summary>
public class LogStatus
{
public string Message { get; set; }
public int EntryCount { get; set; }
public string FilePath { get; set; }
public DateTime LastUpdate { get; set; }
public long FileSizeBytes { get; set; }
public string CurrentLevel { get; set; }
}
/// <summary>
/// 性能数据模型
/// </summary>
public class PerformanceData
{
public double CpuUsage { get; set; }
public long MemoryUsageMB { get; set; }
public int ThreadCount { get; set; }
public TimeSpan RunningTime { get; set; }
public int HandleCount { get; set; }
public double ResponseTimeMs { get; set; }
public DateTime Timestamp { get; set; }
}
/// <summary>
/// 配置档案数据模型
/// </summary>
public class ConfigProfile
{
public string Name { get; set; }
public Dictionary<string, object> Settings { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime LastModified { get; set; }
public bool IsDefault { get; set; }
public string Description { get; set; }
}
#endregion
#region
/// <summary>
/// 默认系统日志管理器实现
/// </summary>
public class DefaultSystemLogManager : ISystemLogManager
{
private readonly string _logDirectory;
private readonly string _logFilePath;
private string _currentLogLevel = "Info";
public DefaultSystemLogManager()
{
_logDirectory = Path.Combine(Environment.CurrentDirectory, "Logs");
_logFilePath = Path.Combine(_logDirectory, "NavisworksTransport.log");
// 确保日志目录存在
if (!Directory.Exists(_logDirectory))
{
Directory.CreateDirectory(_logDirectory);
}
}
public async Task OpenLogViewerAsync()
{
await Task.Run(() =>
{
try
{
// 检查是否存在自定义日志查看器
var logViewerPath = Path.Combine(Environment.CurrentDirectory, "tools", "LogViewer.exe");
if (File.Exists(logViewerPath))
{
// 使用自定义日志查看器
Process.Start(logViewerPath, $"\"{_logFilePath}\"");
}
else if (File.Exists(_logFilePath))
{
// 使用默认文本编辑器打开
Process.Start("notepad.exe", _logFilePath);
}
else
{
MessageBox.Show("日志文件不存在", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
catch (Exception ex)
{
LogManager.Error($"打开日志查看器失败: {ex.Message}", ex);
MessageBox.Show($"打开日志查看器失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
});
}
public async Task ClearLogsAsync()
{
await Task.Run(() =>
{
try
{
if (File.Exists(_logFilePath))
{
// 备份当前日志文件
var backupPath = Path.Combine(_logDirectory, $"backup_{DateTime.Now:yyyyMMdd_HHmmss}.log");
File.Move(_logFilePath, backupPath);
LogManager.Info("日志已清空,备份文件已创建");
}
}
catch (Exception ex)
{
LogManager.Error($"清空日志失败: {ex.Message}", ex);
throw;
}
});
}
public async Task<string> ExportLogsAsync()
{
return await Task.Run(() =>
{
try
{
var exportDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "NavisworksTransport_Logs");
if (!Directory.Exists(exportDirectory))
{
Directory.CreateDirectory(exportDirectory);
}
var exportFileName = $"NavisworksTransport_Log_{DateTime.Now:yyyyMMdd_HHmmss}.zip";
var exportPath = Path.Combine(exportDirectory, exportFileName);
// 这里可以使用System.IO.Compression.ZipFile来创建压缩包
// 包含主日志文件和任何相关的日志文件
if (File.Exists(_logFilePath))
{
var singleLogExportPath = Path.Combine(exportDirectory, $"NavisworksTransport_Log_{DateTime.Now:yyyyMMdd_HHmmss}.log");
File.Copy(_logFilePath, singleLogExportPath);
return singleLogExportPath;
}
return exportPath;
}
catch (Exception ex)
{
LogManager.Error($"导出日志失败: {ex.Message}", ex);
throw;
}
});
}
public async Task<LogStatus> GetLogStatusAsync()
{
return await Task.Run(() =>
{
try
{
var status = new LogStatus
{
FilePath = _logFilePath,
CurrentLevel = _currentLogLevel,
LastUpdate = DateTime.Now
};
if (File.Exists(_logFilePath))
{
var fileInfo = new FileInfo(_logFilePath);
status.FileSizeBytes = fileInfo.Length;
status.LastUpdate = fileInfo.LastWriteTime;
// 估算日志条目数量(简单实现)
var lines = File.ReadAllLines(_logFilePath);
status.EntryCount = lines.Length;
status.Message = $"日志文件正常,共 {status.EntryCount} 条记录";
}
else
{
status.EntryCount = 0;
status.FileSizeBytes = 0;
status.Message = "日志文件不存在";
}
return status;
}
catch (Exception ex)
{
LogManager.Error($"获取日志状态失败: {ex.Message}", ex);
return new LogStatus
{
Message = $"获取日志状态失败: {ex.Message}",
EntryCount = 0,
FilePath = _logFilePath,
CurrentLevel = _currentLogLevel
};
}
});
}
public void SetLogLevel(string level)
{
try
{
_currentLogLevel = level;
// 这里需要与实际的日志系统集成
LogManager.SetLogLevel(level);
LogManager.Info($"日志级别已设置为: {level}");
}
catch (Exception ex)
{
LogManager.Error($"设置日志级别失败: {ex.Message}", ex);
throw;
}
}
public void Dispose()
{
// 清理资源
LogManager.Info("SystemLogManager已清理");
}
}
#endregion
#region
/// <summary>
/// 默认系统配置管理器实现
/// </summary>
public class DefaultSystemConfigManager : ISystemConfigManager
{
private readonly string _configDirectory;
private readonly string _configFilePath;
private Dictionary<string, object> _currentSettings;
private ConfigProfile _currentProfile;
public event EventHandler<ConfigurationChangedEventArgs> ConfigurationChanged;
public DefaultSystemConfigManager()
{
_configDirectory = Path.Combine(Environment.CurrentDirectory, "Config");
_configFilePath = Path.Combine(_configDirectory, "settings.json");
_currentSettings = new Dictionary<string, object>();
// 确保配置目录存在
if (!Directory.Exists(_configDirectory))
{
Directory.CreateDirectory(_configDirectory);
}
// 加载默认配置
LoadDefaultSettings();
}
private void LoadDefaultSettings()
{
_currentSettings = new Dictionary<string, object>
{
{ "AutoSaveEnabled", true },
{ "AutoSaveInterval", 300 },
{ "DebugModeEnabled", false },
{ "LogLevel", "Info" },
{ "WorkingDirectory", Environment.CurrentDirectory },
{ "MaxMemoryUsageMB", 1024 },
{ "PerformanceMonitoringEnabled", true }
};
_currentProfile = new ConfigProfile
{
Name = "默认配置",
Settings = new Dictionary<string, object>(_currentSettings),
CreatedAt = DateTime.Now,
LastModified = DateTime.Now,
IsDefault = true,
Description = "系统默认配置档案"
};
}
public void SetAutoSaveEnabled(bool enabled)
{
SetSetting("AutoSaveEnabled", enabled);
}
public void SetDebugMode(bool enabled)
{
SetSetting("DebugModeEnabled", enabled);
}
public void SetAutoSaveInterval(int seconds)
{
SetSetting("AutoSaveInterval", seconds);
}
private void SetSetting(string key, object value)
{
try
{
var oldValue = _currentSettings.ContainsKey(key) ? _currentSettings[key] : null;
_currentSettings[key] = value;
// 触发配置变更事件
ConfigurationChanged?.Invoke(this, new ConfigurationChangedEventArgs
{
ConfigKey = key,
OldValue = oldValue,
NewValue = value,
ProfileName = _currentProfile?.Name,
Timestamp = DateTime.Now
});
LogManager.Info($"配置项已更新: {key} = {value}");
}
catch (Exception ex)
{
LogManager.Error($"设置配置项失败 {key}: {ex.Message}", ex);
throw;
}
}
public async Task SaveConfigAsync()
{
await Task.Run(() =>
{
try
{
// 这里应该实现JSON序列化保存
// var json = JsonConvert.SerializeObject(_currentSettings, Formatting.Indented);
// File.WriteAllText(_configFilePath, json);
LogManager.Info("配置已保存到文件");
}
catch (Exception ex)
{
LogManager.Error($"保存配置失败: {ex.Message}", ex);
throw;
}
});
}
public async Task LoadConfigAsync()
{
await Task.Run(() =>
{
try
{
if (File.Exists(_configFilePath))
{
// var json = File.ReadAllText(_configFilePath);
// _currentSettings = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
LogManager.Info("配置已从文件加载");
}
else
{
LoadDefaultSettings();
LogManager.Info("使用默认配置");
}
}
catch (Exception ex)
{
LogManager.Error($"加载配置失败: {ex.Message}", ex);
LoadDefaultSettings();
}
});
}
public T GetSetting<T>(string key, T defaultValue = default(T))
{
try
{
if (_currentSettings.ContainsKey(key))
{
return (T)Convert.ChangeType(_currentSettings[key], typeof(T));
}
return defaultValue;
}
catch (Exception ex)
{
LogManager.Error($"获取配置项失败 {key}: {ex.Message}", ex);
return defaultValue;
}
}
public void Dispose()
{
try
{
// 自动保存配置
SaveConfigAsync().Wait(5000); // 等待最多5秒
LogManager.Info("SystemConfigManager已清理");
}
catch (Exception ex)
{
LogManager.Error($"SystemConfigManager清理失败: {ex.Message}", ex);
}
}
}
#endregion
#region
/// <summary>
/// 默认性能监控器实现
/// </summary>
public class DefaultPerformanceMonitor : IPerformanceMonitor
{
private readonly Process _currentProcess;
private bool _isMonitoring;
private readonly List<PerformanceData> _performanceHistory;
private readonly object _lockObject = new object();
public event EventHandler<PerformanceAlertEventArgs> PerformanceAlert;
public DefaultPerformanceMonitor()
{
_currentProcess = Process.GetCurrentProcess();
_performanceHistory = new List<PerformanceData>();
_isMonitoring = false;
}
public async Task<PerformanceData> GetCurrentPerformanceAsync()
{
return await Task.Run(() =>
{
try
{
_currentProcess.Refresh();
var performanceData = new PerformanceData
{
MemoryUsageMB = _currentProcess.WorkingSet64 / (1024 * 1024),
ThreadCount = _currentProcess.Threads.Count,
HandleCount = _currentProcess.HandleCount,
RunningTime = DateTime.Now - _currentProcess.StartTime,
Timestamp = DateTime.Now,
CpuUsage = GetCpuUsage(), // 需要实现CPU使用率获取
ResponseTimeMs = GetResponseTime() // 需要实现响应时间测量
};
// 检查性能阈值
CheckPerformanceThresholds(performanceData);
lock (_lockObject)
{
_performanceHistory.Add(performanceData);
// 保持历史记录在合理范围内最多保留1000条记录
if (_performanceHistory.Count > 1000)
{
_performanceHistory.RemoveAt(0);
}
}
return performanceData;
}
catch (Exception ex)
{
LogManager.Error($"获取性能数据失败: {ex.Message}", ex);
throw;
}
});
}
private double GetCpuUsage()
{
// 简单实现实际应该使用PerformanceCounter或更准确的方法
try
{
return _currentProcess.TotalProcessorTime.TotalMilliseconds / Environment.TickCount * 100;
}
catch
{
return 0.0;
}
}
private double GetResponseTime()
{
// 这里应该实现响应时间测量逻辑
// 可以通过测试关键操作的执行时间来获得
return 50.0; // 模拟值
}
private void CheckPerformanceThresholds(PerformanceData data)
{
// 内存使用率检查超过512MB警告
if (data.MemoryUsageMB > 512)
{
PerformanceAlert?.Invoke(this, new PerformanceAlertEventArgs
{
AlertType = PerformanceAlertType.MemoryHigh,
Message = $"内存使用量较高: {data.MemoryUsageMB}MB",
Value = data.MemoryUsageMB,
Threshold = 512,
Timestamp = DateTime.Now
});
}
// 线程数量检查超过50个线程警告
if (data.ThreadCount > 50)
{
PerformanceAlert?.Invoke(this, new PerformanceAlertEventArgs
{
AlertType = PerformanceAlertType.ThreadCountHigh,
Message = $"线程数量较多: {data.ThreadCount}个",
Value = data.ThreadCount,
Threshold = 50,
Timestamp = DateTime.Now
});
}
// CPU使用率检查超过80%警告)
if (data.CpuUsage > 80)
{
PerformanceAlert?.Invoke(this, new PerformanceAlertEventArgs
{
AlertType = PerformanceAlertType.CpuHigh,
Message = $"CPU使用率较高: {data.CpuUsage:F1}%",
Value = data.CpuUsage,
Threshold = 80,
Timestamp = DateTime.Now
});
}
}
public async Task StartMonitoringAsync()
{
await Task.Run(() =>
{
_isMonitoring = true;
LogManager.Info("性能监控已启动");
});
}
public async Task StopMonitoringAsync()
{
await Task.Run(() =>
{
_isMonitoring = false;
LogManager.Info("性能监控已停止");
});
}
public List<PerformanceData> GetPerformanceHistory(TimeSpan? timeRange = null)
{
lock (_lockObject)
{
if (timeRange.HasValue)
{
var cutoffTime = DateTime.Now - timeRange.Value;
return _performanceHistory.Where(p => p.Timestamp >= cutoffTime).ToList();
}
return new List<PerformanceData>(_performanceHistory);
}
}
public void Dispose()
{
try
{
_isMonitoring = false;
_currentProcess?.Dispose();
LogManager.Info("PerformanceMonitor已清理");
}
catch (Exception ex)
{
LogManager.Error($"PerformanceMonitor清理失败: {ex.Message}", ex);
}
}
}
#endregion
#region
/// <summary>
/// 默认模型分割器管理器实现
/// </summary>
public class DefaultModelSplitterManager : IModelSplitterManager
{
private bool _isRunning;
private string _outputDirectory;
public bool CanRun => !_isRunning && HasValidModel();
public DefaultModelSplitterManager()
{
_outputDirectory = Path.Combine(Environment.CurrentDirectory, "ModelSplitter", "Output");
if (!Directory.Exists(_outputDirectory))
{
Directory.CreateDirectory(_outputDirectory);
}
}
private bool HasValidModel()
{
try
{
// 检查Navisworks中是否有已加载的模型
var document = Autodesk.Navisworks.Api.Application.ActiveDocument;
return document != null && document.Models != null && document.Models.Count > 0;
}
catch
{
return false;
}
}
public async Task<bool> RunModelSplitterAsync()
{
if (!CanRun)
{
LogManager.Warning("模型分割器无法运行:条件不满足");
return false;
}
return await Task.Run(() =>
{
try
{
_isRunning = true;
LogManager.Info("开始模型分层拆分");
// 这里应该实现实际的模型分割逻辑
// 1. 获取当前Navisworks文档
// 2. 按照楼层、区域或其他标准进行分割
// 3. 导出各个分割后的模型
var document = Autodesk.Navisworks.Api.Application.ActiveDocument;
if (document?.Models != null)
{
// 模拟分割过程
System.Threading.Thread.Sleep(2000);
// 实际实现中这里会调用ModelSplitterManager的分割逻辑
// var splitterResult = ModelSplitterManager.SplitByFloors(document);
LogManager.Info("模型分层拆分完成");
return true;
}
return false;
}
catch (Exception ex)
{
LogManager.Error($"模型分割器运行失败: {ex.Message}", ex);
return false;
}
finally
{
_isRunning = false;
}
});
}
public async Task ConfigureAsync()
{
await Task.Run(() =>
{
try
{
// 这里可以打开模型分割器的配置对话框
// 或者加载配置设置
LogManager.Info("模型分割器配置界面已打开");
}
catch (Exception ex)
{
LogManager.Error($"配置模型分割器失败: {ex.Message}", ex);
}
});
}
public void Dispose()
{
_isRunning = false;
LogManager.Info("ModelSplitterManager已清理");
}
}
#endregion
}

View File

@ -482,7 +482,132 @@ public void BatchNavisworksOperations(List<ModelItem> items)
8. **线程状态检查**在关键操作前验证线程状态STA
9. **Dispatcher 模式**:后台线程中需要调用 API 时,始终使用 Dispatcher.Invoke
## 11. 参考官方示例
## 11. Transform 变换操作
### 11.1 Transform 相关 API 概念
**核心概念**
- `ModelItem.Transform` - 返回设计文件中的原始变换,只读属性
- `OverridePermanentTransform()` - 应用增量变换(与现有变换叠加)
- `ResetPermanentTransform()` - 清除所有增量变换,恢复到设计文件原始位置
### 11.2 Transform 操作的正确用法
```csharp
// ✅ 获取物体的原始Transform设计文件中的位置
Transform3D originalTransform = modelItem.Transform;
// ✅ 应用增量变换(累积变换)
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { modelItem };
doc.Models.OverridePermanentTransform(modelItems, newTransform, false);
// ✅ 重置到原始位置(清除所有增量变换)
doc.Models.ResetPermanentTransform(modelItems);
```
### 11.3 Transform 操作的关键区别
| API方法 | 作用 | 使用场景 | 注意事项 |
|---------|------|---------|---------|
| `ModelItem.Transform` | 获取原始变换 | 记录物体初始位置 | 只读属性,返回设计文件位置 |
| `OverridePermanentTransform()` | 应用增量变换 | 动画中移动物体 | 与现有变换累积,不是绝对位置 |
| `ResetPermanentTransform()` | 重置到原始位置 | 清除所有移动,恢复初始状态 | 忽略所有之前的变换 |
### 11.4 实际应用案例
**案例1动画系统中的Transform管理**
```csharp
// 动画开始时记录原始位置
private Transform3D _originalTransform;
public void StartAnimation(ModelItem animatedObject)
{
// 记录原始Transform
_originalTransform = animatedObject.Transform;
// 移动到路径起点(增量变换)
var startTransform = Transform3D.CreateTranslation(startPosition);
var modelItems = new ModelItemCollection { animatedObject };
doc.Models.OverridePermanentTransform(modelItems, startTransform, false);
}
public void ResetAnimation()
{
// 动画结束后使用原始Transform恢复位置
var modelItems = new ModelItemCollection { _animatedObject };
doc.Models.OverridePermanentTransform(modelItems, _originalTransform, false);
}
```
**案例2用户手动位置恢复**
```csharp
public void RestoreToOriginalPosition(ModelItem selectedObject)
{
// 不需要记录Transform直接重置到设计文件原始位置
var doc = Application.ActiveDocument;
var modelItems = new ModelItemCollection { selectedObject };
// 清除所有增量变换,恢复到设计文件原始位置
doc.Models.ResetPermanentTransform(modelItems);
}
```
### 11.5 常见Transform问题和解决方案
**问题1位置恢复有偏移**
```csharp
// ❌ 错误:使用增量变换恢复位置
doc.Models.OverridePermanentTransform(modelItems, originalTransform, false);
// 问题:如果物体已经被移动过,这会导致累积偏移
// ✅ 正确:重置到原始位置
doc.Models.ResetPermanentTransform(modelItems);
// 结果:直接恢复到设计文件中的原始位置,无偏移
```
**问题2动画结束后位置不准确**
```csharp
// ✅ 动画系统应该记录原始Transform并使用增量恢复
private Transform3D _originalTransform;
// 动画开始时
_originalTransform = animatedObject.Transform;
// 动画结束时恢复
doc.Models.OverridePermanentTransform(modelItems, _originalTransform, false);
```
**问题3记录Transform但不使用**
```csharp
// ❌ 不必要记录Transform但使用Reset
private Transform3D _originalTransform;
_originalTransform = selectedItem.Transform; // 记录了但不使用
doc.Models.ResetPermanentTransform(modelItems); // 直接重置
// ✅ 简化:直接重置,无需记录
doc.Models.ResetPermanentTransform(modelItems);
```
### 11.6 Transform 最佳实践
1. **选择合适的恢复方式**
- 动画系统:使用 `OverridePermanentTransform` + 原始Transform
- 用户操作:使用 `ResetPermanentTransform` 直接重置
2. **避免不必要的Transform记录**
- 如果只需要恢复到设计文件原始位置,使用 `ResetPermanentTransform`
- 只有需要恢复到特定中间状态时才记录Transform
3. **理解增量vs绝对变换**
- `OverridePermanentTransform` 是增量的,会与现有变换叠加
- `ResetPermanentTransform` 是绝对的,清除所有变换
4. **线程安全**
- 所有Transform操作都必须在主UI线程中执行
- 使用 `Dispatcher.Invoke` 确保线程安全
## 12. 参考官方示例
强烈建议查看以下官方示例了解更多用法:
- `SearchComparisonPlugIn.cs` - 搜索性能对比

View File

@ -559,7 +559,7 @@ namespace NavisworksTransport
{
_pathPointMarkers?.Clear();
// 通知渲染插件更新显示
_renderPlugin?.ClearPathMarkers();
_renderPlugin?.ClearAllPaths();
LogManager.Info("3D路径标记已清除");
}
catch (Exception ex)
@ -591,11 +591,11 @@ namespace NavisworksTransport
}
}
// 同时尝试通过坐标移除3D标记
if (_renderPlugin != null)
// 重新渲染当前路径以反映更改
if (_renderPlugin != null && CurrentRoute != null)
{
_renderPlugin.RemoveMarkerAt(point.Position, 2.0);
LogManager.Info($"已从3D中移除路径点: {point.Name}");
_renderPlugin.RenderPath(CurrentRoute);
LogManager.Info($"已更新路径可视化: {point.Name}");
}
// 触发路径点移除事件
@ -636,9 +636,49 @@ namespace NavisworksTransport
{
try
{
LogManager.WriteLog("[事件清理] ===== 开始执行StopClickTool - 完整事件订阅清理 =====");
// 1. 停用ToolPlugin并清理事件订阅
DeactivateToolPlugin();
// 2. 额外的事件订阅清理 - 确保所有可能的重复订阅都被清除
LogManager.WriteLog("[事件清理] 执行额外的事件订阅清理");
try
{
// 移除所有可能的OnToolPluginMouseClicked订阅
var mouseClickedEvent = typeof(PathClickToolPlugin).GetEvent("MouseClicked");
if (mouseClickedEvent != null)
{
var eventField = typeof(PathClickToolPlugin).GetField("MouseClicked",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
if (eventField != null)
{
var currentDelegate = (MulticastDelegate)eventField.GetValue(null);
if (currentDelegate != null)
{
var invocationList = currentDelegate.GetInvocationList();
LogManager.WriteLog($"[事件清理] 发现 {invocationList.Length} 个事件订阅者");
foreach (var handler in invocationList)
{
if (handler.Target == this && handler.Method.Name == "OnToolPluginMouseClicked")
{
PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked;
LogManager.WriteLog($"[事件清理] 移除了PathPlanningManager.OnToolPluginMouseClicked订阅");
}
}
}
}
}
}
catch (Exception cleanupEx)
{
LogManager.WriteLog($"[事件清理] 额外清理过程异常: {cleanupEx.Message}");
}
// 3. 更新状态
PathEditState = PathEditState.None;
LogManager.Info("点击工具已停止");
LogManager.WriteLog("[事件清理] ===== StopClickTool执行完成所有事件订阅已清理 =====");
}
catch (Exception ex)
{
@ -1068,13 +1108,11 @@ namespace NavisworksTransport
lastPoint.Type = PathPointType.EndPoint;
lastPoint.Name = GeneratePointName(PathPointType.EndPoint);
// 更新3D标记类型
// 更新3D路径可视化
if (_renderPlugin != null)
{
// 移除旧标记
_renderPlugin.RemoveMarkerAt(lastPoint.Position, 2.0);
// 添加终点标记
_renderPlugin.AddCircleMarker(lastPoint.Position, PathPointType.EndPoint, CurrentRoute.Points.Count);
// 重新渲染整个路径以反映类型变更
_renderPlugin.RenderPath(CurrentRoute);
}
LogManager.Info($"已自动设置最后一个点为终点: {lastPoint.Name}");
@ -1908,8 +1946,44 @@ namespace NavisworksTransport
private bool DeactivateToolPlugin()
{
// TODO: 实现ToolPlugin停用逻辑
return true;
if (!_isToolPluginActive)
{
LogManager.WriteLog("[ToolPlugin] ToolPlugin未激活无需停用");
return true;
}
try
{
LogManager.WriteLog("[ToolPlugin] ===== 开始停用ToolPlugin =====");
// 1. 取消事件订阅
LogManager.WriteLog("[ToolPlugin] 步骤1: 取消事件订阅");
PathClickToolPlugin.MouseClicked -= OnToolPluginMouseClicked;
LogManager.WriteLog("[ToolPlugin] ✓ 事件订阅已取消");
// 2. 重置为无活动工具状态
LogManager.WriteLog("[ToolPlugin] 步骤2: 重置为默认工具");
try
{
// 使用Tool.None重置到无活动工具状态让Navisworks处理默认导航
Application.MainDocument.Tool.Value = Tool.None;
LogManager.WriteLog("[ToolPlugin] ✓ 已重置工具为None状态");
}
catch (Exception ex)
{
LogManager.WriteLog($"[ToolPlugin] 重置工具状态失败: {ex.Message}");
}
_isToolPluginActive = false;
LogManager.WriteLog("[ToolPlugin] ===== ToolPlugin停用完成 =====");
return true;
}
catch (Exception ex)
{
LogManager.WriteLog($"[ToolPlugin] 停用异常: {ex.Message}");
LogManager.WriteLog($"[ToolPlugin] 堆栈: {ex.StackTrace}");
return false;
}
}
#endregion
@ -2137,71 +2211,10 @@ namespace NavisworksTransport
return;
}
if (isAutoPath)
{
// 自动路径可视化
var sortedPoints = route.GetSortedPoints();
// 安全显示自动路径,限制显示数量防止崩溃
int maxDisplayPoints = Math.Min(10, sortedPoints.Count); // 最多显示10个点
LogManager.Info($"安全显示自动路径: 原始{sortedPoints.Count}个点,限制显示{maxDisplayPoints}个点");
if (sortedPoints.Count > maxDisplayPoints)
{
// 如果点太多,只显示起点、终点和几个中间点
var displayPoints = new List<PathPoint>
{
sortedPoints[0] // 起点
};
// 添加几个等间距的中间点
for (int i = 1; i < maxDisplayPoints - 1; i++)
{
int index = (int)((double)i / (maxDisplayPoints - 1) * (sortedPoints.Count - 1));
displayPoints.Add(sortedPoints[index]);
}
displayPoints.Add(sortedPoints[sortedPoints.Count - 1]); // 终点
int displayIndex = 0;
foreach (var point in displayPoints)
{
LogManager.Info($"[路径点{displayIndex}] 坐标: ({point.Position.X:F2}, {point.Position.Y:F2}, {point.Position.Z:F2})");
renderPlugin.AddCircleMarker(point.Position, point.Type, -1000 - displayIndex);
displayIndex++;
}
LogManager.Info($"已可视化自动路径: {route.Name},安全显示 {displayIndex} 个关键点和橙色连线");
}
else
{
// 点数较少时完整显示
int displayIndex = 0;
for (int i = 0; i < sortedPoints.Count; i++)
{
var point = sortedPoints[i];
LogManager.Info($"[路径点{displayIndex}] 坐标: ({point.Position.X:F2}, {point.Position.Y:F2}, {point.Position.Z:F2})");
renderPlugin.AddCircleMarker(point.Position, point.Type, -1000 - displayIndex);
displayIndex++;
}
LogManager.Info($"已可视化自动路径: {route.Name},完整显示 {displayIndex} 个路径点和橙色连线");
}
}
else
{
// 手工路径:完整显示,清除所有标记后重绘,使用黑色连线
renderPlugin.ClearAllMarkers();
var sortedPoints = route.GetSortedPoints();
for (int i = 0; i < sortedPoints.Count; i++)
{
var point = sortedPoints[i];
renderPlugin.AddCircleMarker(point.Position, point.Type, i + 1);
}
LogManager.Info($"已绘制路径: {route.Name},包含 {sortedPoints.Count} 个路径点和连线");
}
// 使用新的统一路径渲染API
renderPlugin.RenderPath(route);
LogManager.Info($"已渲染路径: {route.Name},包含 {route.Points.Count} 个路径点");
}
catch (Exception ex)
{

View File

@ -3,9 +3,96 @@ using System.Collections.Generic;
using System.Linq;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Plugins;
using NavisworksTransport.Core;
namespace NavisworksTransport
{
/// <summary>
/// 连线标记,用于渲染路径点之间的连接线
/// </summary>
public class LineMarker
{
/// <summary>
/// 连线起点
/// </summary>
public Point3D StartPoint { get; set; }
/// <summary>
/// 连线终点
/// </summary>
public Point3D EndPoint { get; set; }
/// <summary>
/// 连线颜色
/// </summary>
public Color Color { get; set; }
/// <summary>
/// 连线半径
/// </summary>
public double Radius { get; set; }
/// <summary>
/// 起点在路径中的索引
/// </summary>
public int FromIndex { get; set; }
/// <summary>
/// 终点在路径中的索引
/// </summary>
public int ToIndex { get; set; }
public override string ToString()
{
return $"LineMarker[{FromIndex}->{ToIndex}, 起点=({StartPoint.X:F2},{StartPoint.Y:F2},{StartPoint.Z:F2}), 终点=({EndPoint.X:F2},{EndPoint.Y:F2},{EndPoint.Z:F2})]";
}
}
/// <summary>
/// 路径可视化数据,包含一个完整路径的所有可视化元素
/// </summary>
public class PathVisualization
{
/// <summary>
/// 路径唯一标识
/// </summary>
public string PathId { get; set; }
/// <summary>
/// 路径数据引用
/// </summary>
public PathRoute PathRoute { get; set; }
/// <summary>
/// 点标记集合
/// </summary>
public List<CircleMarker> PointMarkers { get; set; }
/// <summary>
/// 连线标记集合
/// </summary>
public List<LineMarker> LineMarkers { get; set; }
/// <summary>
/// 最后更新时间
/// </summary>
public DateTime LastUpdated { get; set; }
/// <summary>
/// 构造函数
/// </summary>
public PathVisualization()
{
PointMarkers = new List<CircleMarker>();
LineMarkers = new List<LineMarker>();
LastUpdated = DateTime.Now;
}
public override string ToString()
{
return $"PathVisualization[PathId={PathId}, 点数={PointMarkers.Count}, 连线数={LineMarkers.Count}]";
}
}
/// <summary>
/// 路径点圆形标记渲染插件
/// 使用Graphics.Circle在3D空间绘制圆形标记
@ -14,9 +101,11 @@ namespace NavisworksTransport
public class PathPointRenderPlugin : RenderPlugin
{
private readonly object _lockObject = new object();
private List<CircleMarker> _circleMarkers = new List<CircleMarker>();
private Dictionary<string, PathVisualization> _pathVisualizations = new Dictionary<string, PathVisualization>();
private bool _isEnabled = true;
private int _lastAutoMarkersCount = -1; // 用于检测自动路径标记数量变化
// 为向后兼容保留的旧字段
private List<CircleMarker> _circleMarkers = new List<CircleMarker>();
// 静态实例,用于外部访问
private static PathPointRenderPlugin _instance;
@ -52,7 +141,21 @@ namespace NavisworksTransport
}
/// <summary>
/// 当前圆形标记数量
/// 当前路径总数
/// </summary>
public int PathCount
{
get
{
lock (_lockObject)
{
return _pathVisualizations.Count;
}
}
}
/// <summary>
/// 当前点标记总数
/// </summary>
public int MarkerCount
{
@ -60,7 +163,7 @@ namespace NavisworksTransport
{
lock (_lockObject)
{
return _circleMarkers.Count;
return _pathVisualizations.Values.Sum(v => v.PointMarkers.Count);
}
}
}
@ -83,85 +186,38 @@ namespace NavisworksTransport
return; // 静默返回,避免日志泛滥
}
// 检查是否有标记需要渲染
int markerCount;
// 检查是否有路径需要渲染
int pathCount;
lock (_lockObject)
{
markerCount = _circleMarkers.Count;
pathCount = _pathVisualizations.Count;
}
if (markerCount == 0) return;
if (pathCount == 0) return;
// 使用BeginModelContext确保正确的渲染上下文
graphics.BeginModelContext();
// 缓存转换系数,避免重复计算
double lineRadiusInMeters = 0.2;
double lineRadiusInModelUnits = lineRadiusInMeters * GetMetersToModelUnitsConversionFactor();
lock (_lockObject)
{
// 优化:预过滤和排序,减少重复计算
var manualMarkers = _circleMarkers.Where(m => m.SequenceNumber >= 0)
.OrderBy(m => m.SequenceNumber)
.ToArray(); // 转为数组提高性能
var autoMarkers = _circleMarkers.Where(m => m.SequenceNumber < -999)
.OrderByDescending(m => m.SequenceNumber)
.ToArray();
// 绘制连接线段(仅在有多个标记时)
if (markerCount > 1)
foreach (var visualization in _pathVisualizations.Values)
{
// 1. 绘制手动路径连线(正序号,黑色)
if (manualMarkers.Length > 1)
// 渲染所有点标记
foreach (var pointMarker in visualization.PointMarkers)
{
graphics.Color(Color.FromByteRGB(0, 0, 0), 1.0);
for (int i = 0; i < manualMarkers.Length - 1; i++)
{
var current = manualMarkers[i];
var next = manualMarkers[i + 1];
// 只为连续序号的点绘制连线
if (next.SequenceNumber == current.SequenceNumber + 1)
{
graphics.Cylinder(current.Center, next.Center, lineRadiusInModelUnits);
}
}
graphics.Color(pointMarker.Color, pointMarker.Alpha);
graphics.Sphere(pointMarker.Center, pointMarker.Radius);
}
// 2. 绘制自动路径连线(负序号-1000系列橙色
if (autoMarkers.Length > 1)
// 渲染所有连线
LogManager.WriteLog($"[渲染连线] 路径 {visualization.PathId} 有 {visualization.LineMarkers.Count} 条连线");
foreach (var lineMarker in visualization.LineMarkers)
{
graphics.Color(Color.FromByteRGB(255, 165, 0), 1.0);
// 只在标记数量变化时输出日志
if (autoMarkers.Length != _lastAutoMarkersCount)
{
LogManager.WriteLog($"[自动路径连线] 找到 {autoMarkers.Length} 个自动路径标记");
_lastAutoMarkersCount = autoMarkers.Length;
}
for (int i = 0; i < autoMarkers.Length - 1; i++)
{
var current = autoMarkers[i];
var next = autoMarkers[i + 1];
// 为连续负序号的点绘制连线
if (current.SequenceNumber - next.SequenceNumber == 1)
{
graphics.Cylinder(current.Center, next.Center, lineRadiusInModelUnits);
}
}
graphics.Color(lineMarker.Color, 1.0);
graphics.Cylinder(lineMarker.StartPoint, lineMarker.EndPoint, lineMarker.Radius);
LogManager.WriteLog($"[渲染连线] 绘制连线 {lineMarker.FromIndex}->{lineMarker.ToIndex}, 半径={lineMarker.Radius:F3}");
}
}
// 绘制所有球体标记(使用原始集合避免重复过滤)
foreach (var marker in _circleMarkers)
{
graphics.Color(marker.Color, marker.Alpha);
graphics.Sphere(marker.Center, marker.Radius);
}
}
graphics.EndModelContext();
@ -174,42 +230,371 @@ namespace NavisworksTransport
}
}
#region
/// <summary>
/// 添加球体标记
/// 渲染完整路径
/// </summary>
/// <param name="center">圆心位置</param>
/// <param name="pointType">路径点类型</param>
/// <param name="sequenceNumber">序号</param>
public void AddCircleMarker(Point3D center, PathPointType pointType, int sequenceNumber)
/// <param name="pathRoute">路径数据</param>
public void RenderPath(PathRoute pathRoute)
{
if (pathRoute == null)
{
LogManager.WriteLog("[路径渲染] 路径数据为空");
return;
}
try
{
var marker = new CircleMarker
{
Center = center,
Normal = new Vector3D(0, 0, 1), // 垂直向上
Radius = GetRadiusForPointType(pointType),
Color = GetColorForPointType(pointType),
Alpha = 1.0, // 完全不透明
Filled = true, // 实心圆
PointType = pointType,
SequenceNumber = sequenceNumber,
CreatedTime = DateTime.Now
var visualization = new PathVisualization
{
PathId = pathRoute.Id,
PathRoute = pathRoute
};
BuildVisualization(visualization);
lock (_lockObject)
{
_circleMarkers.Add(marker);
_pathVisualizations[pathRoute.Id] = visualization;
}
//LogManager.WriteLog($"[圆形标记] 添加圆形标记: 类型={pointType}, 序号={sequenceNumber}, 中心=({center.X:F2}, {center.Y:F2}, {center.Z:F2})");
// 触发视图刷新
LogManager.WriteLog($"[路径渲染] 渲染路径: {pathRoute.Name}, 点数: {pathRoute.Points.Count}");
RequestViewRefresh();
}
catch (Exception ex)
{
LogManager.WriteLog($"[圆形标记] 添加标记失败: {ex.Message}");
LogManager.WriteLog($"[路径渲染] 渲染路径失败: {ex.Message}");
}
}
/// <summary>
/// 刷新路径可视化
/// </summary>
/// <param name="pathId">路径ID</param>
public void RefreshPath(string pathId)
{
lock (_lockObject)
{
if (_pathVisualizations.TryGetValue(pathId, out var visualization))
{
BuildVisualization(visualization);
LogManager.WriteLog($"[路径刷新] 刷新路径: {pathId}");
RequestViewRefresh();
}
}
}
/// <summary>
/// 移除路径
/// </summary>
/// <param name="pathId">路径ID</param>
public void RemovePath(string pathId)
{
lock (_lockObject)
{
if (_pathVisualizations.Remove(pathId))
{
LogManager.WriteLog($"[路径移除] 移除路径: {pathId}");
RequestViewRefresh();
}
}
}
/// <summary>
/// 清空所有路径
/// </summary>
public void ClearAllPaths()
{
lock (_lockObject)
{
var count = _pathVisualizations.Count;
_pathVisualizations.Clear();
LogManager.WriteLog($"[路径清空] 清空所有路径,共{count}个");
RequestViewRefresh();
}
}
/// <summary>
/// 构建路径可视化
/// </summary>
/// <param name="visualization">路径可视化对象</param>
private void BuildVisualization(PathVisualization visualization)
{
// 清空现有标记
visualization.PointMarkers.Clear();
visualization.LineMarkers.Clear();
var points = visualization.PathRoute.Points;
if (points.Count == 0) return;
// 按索引排序点
var sortedPoints = points.OrderBy(p => p.Index).ToList();
// 构建点标记
foreach (var point in sortedPoints)
{
var pointMarker = CreatePointMarker(point);
visualization.PointMarkers.Add(pointMarker);
}
// 构建连线标记(按排序后的顺序连接)
for (int i = 0; i < sortedPoints.Count - 1; i++)
{
var currentPoint = sortedPoints[i];
var nextPoint = sortedPoints[i + 1];
var lineMarker = new LineMarker
{
StartPoint = currentPoint.Position,
EndPoint = nextPoint.Position,
Color = GetLineColor(),
Radius = GetLineRadius(),
FromIndex = currentPoint.Index,
ToIndex = nextPoint.Index
};
visualization.LineMarkers.Add(lineMarker);
LogManager.WriteLog($"[连线构建] 创建连线: {currentPoint.Index} -> {nextPoint.Index}, " +
$"起点({currentPoint.Position.X:F2}, {currentPoint.Position.Y:F2}, {currentPoint.Position.Z:F2}) -> " +
$"终点({nextPoint.Position.X:F2}, {nextPoint.Position.Y:F2}, {nextPoint.Position.Z:F2})");
}
visualization.LastUpdated = DateTime.Now;
}
/// <summary>
/// 创建点标记
/// </summary>
/// <param name="point">路径点</param>
/// <returns>圆形标记</returns>
private CircleMarker CreatePointMarker(PathPoint point)
{
return new CircleMarker
{
Center = point.Position,
Normal = new Vector3D(0, 0, 1),
Radius = GetRadiusForPointType(point.Type),
Color = GetColorForPointType(point.Type),
Alpha = 1.0,
Filled = true,
PointType = point.Type,
SequenceNumber = point.Index, // 使用Index而不是任意序号
CreatedTime = DateTime.Now
};
}
/// <summary>
/// 获取连线颜色(统一使用橙色)
/// </summary>
/// <returns>连线颜色</returns>
private Color GetLineColor()
{
return Color.FromByteRGB(255, 165, 0); // 统一使用橙色连线
}
/// <summary>
/// 获取连线半径
/// </summary>
/// <returns>连线半径</returns>
private double GetLineRadius()
{
double lineRadiusInMeters = 0.2;
return lineRadiusInMeters * GetMetersToModelUnitsConversionFactor();
}
/// <summary>
/// 添加路径点到指定路径
/// </summary>
/// <param name="pathId">路径ID</param>
/// <param name="newPoint">新的路径点</param>
/// <param name="insertIndex">插入位置索引,-1表示添加到末尾</param>
public void AddPointToPath(string pathId, PathPoint newPoint, int insertIndex = -1)
{
var visualization = GetPathVisualization(pathId);
if (visualization == null)
{
LogManager.WriteLog($"[路径编辑] 未找到路径: {pathId}");
return;
}
try
{
var pathRoute = visualization.PathRoute;
if (insertIndex == -1)
{
// 添加到末尾
newPoint.Index = pathRoute.Points.Count;
pathRoute.Points.Add(newPoint);
}
else
{
// 插入到指定位置
pathRoute.Points.Insert(insertIndex, newPoint);
// 重新分配所有点的索引
ReindexPoints(pathRoute);
}
// 重建可视化
BuildVisualization(visualization);
LogManager.WriteLog($"[路径编辑] 添加路径点: {newPoint.Name} 到路径 {pathId}");
RequestViewRefresh();
}
catch (Exception ex)
{
LogManager.WriteLog($"[路径编辑] 添加路径点失败: {ex.Message}");
}
}
/// <summary>
/// 从指定路径移除路径点
/// </summary>
/// <param name="pathId">路径ID</param>
/// <param name="pointIndex">要移除的点索引</param>
public void RemovePointFromPath(string pathId, int pointIndex)
{
var visualization = GetPathVisualization(pathId);
if (visualization == null)
{
LogManager.WriteLog($"[路径编辑] 未找到路径: {pathId}");
return;
}
try
{
var pathRoute = visualization.PathRoute;
var pointToRemove = pathRoute.Points.FirstOrDefault(p => p.Index == pointIndex);
if (pointToRemove != null)
{
pathRoute.Points.Remove(pointToRemove);
// 重新分配索引
ReindexPoints(pathRoute);
// 重建可视化
BuildVisualization(visualization);
LogManager.WriteLog($"[路径编辑] 移除路径点: 索引 {pointIndex} 从路径 {pathId}");
RequestViewRefresh();
}
else
{
LogManager.WriteLog($"[路径编辑] 未找到索引为 {pointIndex} 的路径点");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[路径编辑] 移除路径点失败: {ex.Message}");
}
}
/// <summary>
/// 更新指定路径中的路径点
/// </summary>
/// <param name="pathId">路径ID</param>
/// <param name="pointIndex">要更新的点索引</param>
/// <param name="updatedPoint">更新后的路径点</param>
public void UpdatePointInPath(string pathId, int pointIndex, PathPoint updatedPoint)
{
var visualization = GetPathVisualization(pathId);
if (visualization == null)
{
LogManager.WriteLog($"[路径编辑] 未找到路径: {pathId}");
return;
}
try
{
var pathRoute = visualization.PathRoute;
var existingPoint = pathRoute.Points.FirstOrDefault(p => p.Index == pointIndex);
if (existingPoint != null)
{
// 保持索引不变
updatedPoint.Index = pointIndex;
// 替换点
var index = pathRoute.Points.IndexOf(existingPoint);
pathRoute.Points[index] = updatedPoint;
// 重建可视化
BuildVisualization(visualization);
LogManager.WriteLog($"[路径编辑] 更新路径点: 索引 {pointIndex} 在路径 {pathId}");
RequestViewRefresh();
}
else
{
LogManager.WriteLog($"[路径编辑] 未找到索引为 {pointIndex} 的路径点");
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[路径编辑] 更新路径点失败: {ex.Message}");
}
}
/// <summary>
/// 重新分配路径点索引
/// </summary>
/// <param name="pathRoute">路径对象</param>
private void ReindexPoints(PathRoute pathRoute)
{
// 按照当前在List中的位置重新分配连续索引
for (int i = 0; i < pathRoute.Points.Count; i++)
{
pathRoute.Points[i].Index = i;
}
}
/// <summary>
/// 获取路径可视化对象
/// </summary>
/// <param name="pathId">路径ID</param>
/// <returns>路径可视化对象如果不存在返回null</returns>
private PathVisualization GetPathVisualization(string pathId)
{
lock (_lockObject)
{
_pathVisualizations.TryGetValue(pathId, out var visualization);
return visualization;
}
}
#endregion
#region
/// <summary>
/// [已过时] 添加球体标记 - 请使用RenderPath方法代替
/// </summary>
/// <param name="center">圆心位置</param>
/// <param name="pointType">路径点类型</param>
/// <param name="sequenceNumber">序号</param>
[Obsolete("此方法已过时请使用RenderPath方法进行统一的路径可视化", false)]
public void AddCircleMarker(Point3D center, PathPointType pointType, int sequenceNumber)
{
LogManager.WriteLog($"[兼容性警告] 使用了已过时的AddCircleMarker方法建议使用RenderPath方法");
try
{
// 为了兼容性,创建一个临时路径
var tempPath = new PathRoute($"TempPath_{Guid.NewGuid().ToString("N").Substring(0, 8)}")
{
Id = $"temp_{sequenceNumber}_{DateTime.Now.Ticks}"
};
var pathPoint = new PathPoint(center, $"Point_{sequenceNumber}", pointType)
{
Index = 0
};
tempPath.Points.Add(pathPoint);
// 使用新的渲染方法
RenderPath(tempPath);
}
catch (Exception ex)
{
LogManager.WriteLog($"[兼容性标记] 添加标记失败: {ex.Message}");
}
}
@ -255,145 +640,58 @@ namespace NavisworksTransport
}
/// <summary>
/// 清除所有球体标记
/// [已过时] 清除所有球体标记 - 请使用ClearAllPaths方法代替
/// </summary>
[Obsolete("此方法已过时请使用ClearAllPaths方法", false)]
public void ClearAllMarkers()
{
try
{
int removedCount = 0;
lock (_lockObject)
{
removedCount = _circleMarkers.Count;
_circleMarkers.Clear();
}
LogManager.WriteLog($"[球体标记] 清除所有标记,共移除 {removedCount} 个球体标记");
if (removedCount > 0)
{
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[球体标记] 清除标记失败: {ex.Message}");
}
LogManager.WriteLog($"[兼容性警告] 使用了已过时的ClearAllMarkers方法建议使用ClearAllPaths方法");
ClearAllPaths();
}
/// <summary>
/// 清除所有自动路径标记(序列号-1000系列
/// [已过时] 清除所有自动路径标记 - 请使用ClearAllPaths方法代替
/// </summary>
[Obsolete("此方法已过时请使用ClearAllPaths方法", false)]
public void ClearAutoPathMarkers()
{
try
{
int removedCount = 0;
lock (_lockObject)
{
// 移除所有序列号小于-999的标记自动路径标记
for (int i = _circleMarkers.Count - 1; i >= 0; i--)
{
var marker = _circleMarkers[i];
if (marker.SequenceNumber < -999)
{
_circleMarkers.RemoveAt(i);
removedCount++;
}
}
// 重置自动路径标记计数
_lastAutoMarkersCount = -1;
}
LogManager.WriteLog($"[球体标记] 清除自动路径标记,共移除 {removedCount} 个自动路径点");
if (removedCount > 0)
{
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[球体标记] 清除自动路径标记失败: {ex.Message}");
}
LogManager.WriteLog($"[兼容性警告] 使用了已过时的ClearAutoPathMarkers方法建议使用ClearAllPaths方法");
ClearAllPaths();
}
/// <summary>
/// 清除手动路径标记(序列号>=0
/// [已过时] 清除手动路径标记 - 请使用ClearAllPaths方法代替
/// </summary>
[Obsolete("此方法已过时请使用ClearAllPaths方法", false)]
public void ClearManualPathMarkers()
{
try
{
int removedCount = 0;
lock (_lockObject)
{
// 移除所有序列号>=0的标记手动路径标记
for (int i = _circleMarkers.Count - 1; i >= 0; i--)
{
var marker = _circleMarkers[i];
if (marker.SequenceNumber >= 0)
{
_circleMarkers.RemoveAt(i);
removedCount++;
}
}
}
LogManager.WriteLog($"[球体标记] 清除手动路径标记,共移除 {removedCount} 个手动路径点");
if (removedCount > 0)
{
RequestViewRefresh();
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[球体标记] 清除手动路径标记失败: {ex.Message}");
}
LogManager.WriteLog($"[兼容性警告] 使用了已过时的ClearManualPathMarkers方法建议使用ClearAllPaths方法");
ClearAllPaths();
}
/// <summary>
/// 获取所有球体标记的副本
/// [已过时] 获取所有球体标记的副本 - 此方法不再适用于新的路径系统
/// </summary>
/// <returns>标记列表</returns>
/// <returns>空列表</returns>
[Obsolete("此方法已过时,新的路径系统不使用独立的标记概念", false)]
public List<CircleMarker> GetAllMarkers()
{
lock (_lockObject)
{
return new List<CircleMarker>(_circleMarkers);
}
LogManager.WriteLog($"[兼容性警告] 使用了已过时的GetAllMarkers方法新系统不再支持独立标记");
return new List<CircleMarker>();
}
/// <summary>
/// 根据序号更新一个已存在的球体标记
/// [已过时] 根据序号更新一个已存在的球体标记 - 请使用UpdatePointInPath方法代替
/// </summary>
[Obsolete("此方法已过时请使用UpdatePointInPath方法更新路径中的点", false)]
public void UpdateMarker(int sequenceNumber, Color newColor, double newRadius)
{
try
{
lock (_lockObject)
{
var markerToUpdate = _circleMarkers.FirstOrDefault(m => m.SequenceNumber == sequenceNumber);
if (markerToUpdate != null)
{
markerToUpdate.Color = newColor;
markerToUpdate.Radius = newRadius;
LogManager.WriteLog($"[球体标记] 更新标记: 序号={sequenceNumber}, 新颜色={newColor}, 新半径={newRadius:F2}");
RequestViewRefresh();
}
}
}
catch (Exception ex)
{
LogManager.WriteLog($"[球体标记] 更新标记失败: {ex.Message}");
}
LogManager.WriteLog($"[兼容性警告] 使用了已过时的UpdateMarker方法请使用UpdatePointInPath方法");
// 由于新系统没有直接的序号对应关系,这个方法不再有效
}
#endregion
#region
/// <summary>

View File

@ -31,34 +31,7 @@
</TabItem>
<TabItem Header="系统管理" Name="SystemManagementTab">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Margin="10">
<GroupBox Header="日志管理" Margin="0,10" Height="100">
<StackPanel Orientation="Horizontal" Margin="10">
<Button Content="查看日志" Name="ViewLogButton" Margin="0,0,10,0"/>
<Button Content="清空日志" Name="ClearLogButton" Margin="0,0,10,0"/>
<Button Content="导出日志" Name="ExportLogButton"/>
</StackPanel>
</GroupBox>
<GroupBox Header="插件设置" Margin="0,10" Height="100">
<StackPanel Orientation="Horizontal" Margin="10">
<Button Content="设置选项" Name="SettingsButton" Margin="0,0,10,0"/>
<Button Content="重置设置" Name="ResetSettingsButton"/>
</StackPanel>
</GroupBox>
<GroupBox Header="系统信息" Margin="0,10" Height="160">
<StackPanel Margin="10">
<Label Content="插件版本: v1.0" Name="VersionLabel"/>
<Label Content="Navisworks版本: 2026" Name="NavisVersionLabel"/>
<Label Content="系统状态: 正常" Name="SystemStatusLabel"/>
<Button Content="检查更新" Name="CheckUpdateButton" Margin="0,10,0,0"/>
</StackPanel>
</GroupBox>
</StackPanel>
</ScrollViewer>
<views:SystemManagementView x:Name="SystemManagementView"/>
</TabItem>
</TabControl>

View File

@ -15,6 +15,7 @@ namespace NavisworksTransport.UI.WPF
{
// ViewModel实例
public LogisticsControlViewModel ViewModel { get; private set; }
public SystemManagementViewModel SystemManagementViewModel { get; private set; }
// 分层管理视图
private LayerManagementView _layerManagementView;
@ -32,7 +33,11 @@ namespace NavisworksTransport.UI.WPF
// 创建并设置ViewModel
ViewModel = new LogisticsControlViewModel();
SystemManagementViewModel = new SystemManagementViewModel();
DataContext = ViewModel;
// 为SystemManagementView设置独立的DataContext
SystemManagementView.DataContext = SystemManagementViewModel;
InitializeSession();
InitializeViews();
@ -68,6 +73,9 @@ namespace NavisworksTransport.UI.WPF
// 初始化PathEditingView
InitializePathEditingView();
// 初始化SystemManagementView
InitializeSystemManagementView();
LogManager.Info("子视图初始化完成");
}
@ -180,6 +188,24 @@ namespace NavisworksTransport.UI.WPF
LogManager.Error($"初始化PathEditingView失败: {ex.Message}");
}
}
/// <summary>
/// 初始化SystemManagementView
/// </summary>
private void InitializeSystemManagementView()
{
try
{
if (SystemManagementView?.DataContext != null)
{
LogManager.Info("SystemManagementView初始化完成");
}
}
catch (Exception ex)
{
LogManager.Error($"初始化SystemManagementView失败: {ex.Message}");
}
}
/// <summary>
/// 初始化事件处理器
@ -282,6 +308,9 @@ namespace NavisworksTransport.UI.WPF
// 清理PathEditingView
PathEditingView?.Cleanup();
// 清理SystemManagementViewModel
SystemManagementViewModel?.Cleanup();
// TODO: 清理路径规划管理器事件订阅
// 暂时注释掉,避免编译错误

View File

@ -60,6 +60,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private bool _hasSelectedAnimatedObject = false;
private bool _canGenerateAnimation = false;
private string _generationStatus = "就绪";
#endregion
@ -856,6 +857,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
/// <summary>
/// 执行清除移动物体命令
/// </summary>
/// <summary>
/// 执行清除移动物体命令
/// </summary>
@ -863,13 +867,44 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
try
{
LogManager.Info("开始清除移动物体选择并恢复原始位置");
// 如果有选中的物体,则恢复到原始位置
if (SelectedAnimatedObject != null)
{
try
{
LogManager.Info($"开始恢复物体 '{SelectedAnimatedObject.DisplayName}' 到原始位置");
// 使用ResetPermanentTransform清除所有增量变换恢复到设计文件中的原始位置
var doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
var modelItems = new ModelItemCollection { SelectedAnimatedObject };
doc.Models.ResetPermanentTransform(modelItems);
LogManager.Info($"物体 '{SelectedAnimatedObject.DisplayName}' 已成功恢复到原始位置");
GenerationStatus = "已清除移动物体选择并恢复到原始位置";
}
catch (Exception restoreEx)
{
LogManager.Error($"恢复物体到原始位置时发生错误: {restoreEx.Message}");
GenerationStatus = $"已清除物体选择,但恢复位置失败: {restoreEx.Message}";
}
}
else
{
LogManager.Info("没有选中的物体需要清除");
GenerationStatus = "已清除移动物体选择";
}
// 清理选择状态
SelectedAnimatedObject = null;
GenerationStatus = "已清除移动物体选择";
LogManager.Info("移动物体选择已清除");
LogManager.Info("移动物体选择已完全清除");
}
catch (Exception ex)
{
LogManager.Error($"清除移动物体选择时发生错误: {ex.Message}");
GenerationStatus = $"清除失败: {ex.Message}";
}
}

View File

@ -61,21 +61,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private string _collisionStatus = "就绪";
private string _collisionSummary = "尚未运行碰撞检测";
// 系统管理相关字段
private string _modelSplitterStatus = "就绪";
private ObservableCollection<string> _logLevels;
private string _selectedLogLevel = "Info";
private string _logStatus = "日志系统正常";
private bool _isAutoSaveEnabled = true;
private bool _isDebugModeEnabled = false;
private string _settingsStatus = "设置已加载";
private string _pluginVersion = "v1.0";
private string _navisworksVersion = "2026";
private string _systemStatus = "正常";
private string _systemStatusColor = "Green";
private string _memoryUsage = "0 MB";
private string _runningTime = "00:00:00";
private string _performanceInfo = "性能监控就绪";
#endregion
@ -341,135 +326,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
#endregion
#region
/// <summary>
/// 模型分层拆分状态
/// </summary>
public string ModelSplitterStatus
{
get => _modelSplitterStatus;
set => SetProperty(ref _modelSplitterStatus, value);
}
/// <summary>
/// 日志级别集合
/// </summary>
public ObservableCollection<string> LogLevels
{
get => _logLevels;
set => SetProperty(ref _logLevels, value);
}
/// <summary>
/// 选中的日志级别
/// </summary>
public string SelectedLogLevel
{
get => _selectedLogLevel;
set => SetProperty(ref _selectedLogLevel, value);
}
/// <summary>
/// 日志状态
/// </summary>
public string LogStatus
{
get => _logStatus;
set => SetProperty(ref _logStatus, value);
}
/// <summary>
/// 是否启用自动保存
/// </summary>
public bool IsAutoSaveEnabled
{
get => _isAutoSaveEnabled;
set => SetProperty(ref _isAutoSaveEnabled, value);
}
/// <summary>
/// 是否启用调试模式
/// </summary>
public bool IsDebugModeEnabled
{
get => _isDebugModeEnabled;
set => SetProperty(ref _isDebugModeEnabled, value);
}
/// <summary>
/// 设置状态
/// </summary>
public string SettingsStatus
{
get => _settingsStatus;
set => SetProperty(ref _settingsStatus, value);
}
/// <summary>
/// 插件版本
/// </summary>
public string PluginVersion
{
get => _pluginVersion;
set => SetProperty(ref _pluginVersion, value);
}
/// <summary>
/// Navisworks版本
/// </summary>
public string NavisworksVersion
{
get => _navisworksVersion;
set => SetProperty(ref _navisworksVersion, value);
}
/// <summary>
/// 系统状态
/// </summary>
public string SystemStatus
{
get => _systemStatus;
set => SetProperty(ref _systemStatus, value);
}
/// <summary>
/// 系统状态颜色
/// </summary>
public string SystemStatusColor
{
get => _systemStatusColor;
set => SetProperty(ref _systemStatusColor, value);
}
/// <summary>
/// 内存使用情况
/// </summary>
public string MemoryUsage
{
get => _memoryUsage;
set => SetProperty(ref _memoryUsage, value);
}
/// <summary>
/// 运行时间
/// </summary>
public string RunningTime
{
get => _runningTime;
set => SetProperty(ref _runningTime, value);
}
/// <summary>
/// 性能信息
/// </summary>
public string PerformanceInfo
{
get => _performanceInfo;
set => SetProperty(ref _performanceInfo, value);
}
#endregion
#endregion
@ -480,16 +336,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public ICommand StopAnimationCommand { get; private set; }
public ICommand RunCollisionDetectionCommand { get; private set; }
public ICommand ViewCollisionReportCommand { get; private set; }
public ICommand ModelSplitterCommand { get; private set; }
public ICommand SetLogisticsAttributeCommand { get; private set; }
public ICommand ViewLogCommand { get; private set; }
public ICommand ClearLogCommand { get; private set; }
public ICommand ExportLogCommand { get; private set; }
public ICommand OpenSettingsCommand { get; private set; }
public ICommand ResetSettingsCommand { get; private set; }
public ICommand ImportConfigCommand { get; private set; }
public ICommand CheckUpdateCommand { get; private set; }
public ICommand GeneratePerformanceReportCommand { get; private set; }
#endregion
@ -520,7 +367,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogisticsModels = new ThreadSafeObservableCollection<LogisticsModel>();
AvailableCategories = new ThreadSafeObservableCollection<string>();
AvailableFrameRates = new ThreadSafeObservableCollection<int>();
LogLevels = new ThreadSafeObservableCollection<string>();
// 初始化命令使用新的Command Pattern框架
InitializeCommandsAsync();
@ -563,8 +409,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 初始化动画参数
await InitializeAnimationSettingsAsync();
// 初始化系统管理设置
await InitializeSystemManagementSettingsAsync();
LogManager.Info("LogisticsControlViewModel 初始化完成");
}, "初始化ViewModel");
@ -586,17 +430,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
RunCollisionDetectionCommand = new RelayCommand(async () => await ExecuteRunCollisionDetectionAsync(), () => CanRunCollisionDetection);
ViewCollisionReportCommand = new RelayCommand(async () => await ExecuteViewCollisionReportAsync(), () => HasCollisionResults);
// 系统管理命令
ModelSplitterCommand = new RelayCommand(async () => await ExecuteModelSplitterAsync());
// 物流属性命令
SetLogisticsAttributeCommand = new RelayCommand(async () => await ExecuteSetLogisticsAttributeAsync());
ViewLogCommand = new RelayCommand(async () => await ExecuteViewLogAsync());
ClearLogCommand = new RelayCommand(async () => await ExecuteClearLogAsync());
ExportLogCommand = new RelayCommand(async () => await ExecuteExportLogAsync());
OpenSettingsCommand = new RelayCommand(async () => await ExecuteOpenSettingsAsync());
ResetSettingsCommand = new RelayCommand(async () => await ExecuteResetSettingsAsync());
ImportConfigCommand = new RelayCommand(async () => await ExecuteImportConfigAsync());
CheckUpdateCommand = new RelayCommand(async () => await ExecuteCheckUpdateAsync());
GeneratePerformanceReportCommand = new RelayCommand(async () => await ExecuteGeneratePerformanceReportAsync());
LogManager.Info("命令初始化完成 - 使用新的异步Command Pattern框架");
}, "初始化命令");
@ -644,71 +479,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
/// <summary>
/// 初始化系统管理设置
/// </summary>
private async Task InitializeSystemManagementSettingsAsync()
{
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 初始化日志级别
LogLevels.Clear();
var logLevels = new[] { "Debug", "Info", "Warning", "Error" };
foreach (var level in logLevels)
{
LogLevels.Add(level);
}
SelectedLogLevel = "Info";
// 初始化系统信息
ModelSplitterStatus = "就绪";
LogStatus = "日志系统正常";
SettingsStatus = "设置已加载";
PluginVersion = "v1.0";
NavisworksVersion = "2026";
SystemStatus = "正常";
SystemStatusColor = "Green";
});
// 启动性能监控
StartPerformanceMonitoring();
LogManager.Info("系统管理设置初始化完成");
}, "初始化系统管理设置");
}
/// <summary>
/// 启动性能监控
/// </summary>
private void StartPerformanceMonitoring()
{
var startTime = DateTime.Now;
// 使用定时器更新性能信息
var timer = new System.Windows.Threading.DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(5);
timer.Tick += (s, e) =>
{
try
{
// 更新内存使用
var process = System.Diagnostics.Process.GetCurrentProcess();
var memoryMB = process.WorkingSet64 / (1024 * 1024);
MemoryUsage = $"{memoryMB} MB";
// 更新运行时间
var runTime = DateTime.Now - startTime;
RunningTime = $"{runTime.Hours:D2}:{runTime.Minutes:D2}:{runTime.Seconds:D2}";
// 更新性能信息
PerformanceInfo = $"CPU: 正常, 内存: {memoryMB}MB, 运行时间: {RunningTime}";
}
catch (Exception ex)
{
LogManager.Error($"性能监控更新失败: {ex.Message}");
}
};
timer.Start();
}
#endregion
@ -1057,126 +827,21 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
private void ExecuteViewLog()
{
SafeExecute(() =>
{
// TODO: 实现日志查看功能
StatusText = "打开日志查看器";
LogManager.Info("查看日志");
}, "查看日志");
}
private void ExecuteClearLog()
{
SafeExecute(() =>
{
// TODO: 实现日志清空功能
LogStatus = "日志已清空";
StatusText = "日志已清空";
LogManager.Info("清空日志");
}, "清空日志");
}
private void ExecuteExportLog()
{
SafeExecute(() =>
{
// TODO: 实现日志导出功能
StatusText = "日志导出完成";
LogManager.Info("导出日志");
}, "导出日志");
}
private void ExecuteOpenSettings()
{
SafeExecute(() =>
{
// TODO: 实现设置对话框
StatusText = "打开插件设置";
LogManager.Info("打开设置");
}, "打开设置");
}
private void ExecuteResetSettings()
{
SafeExecute(() =>
{
// TODO: 实现设置重置功能
SettingsStatus = "设置已重置为默认值";
IsAutoSaveEnabled = true;
IsDebugModeEnabled = false;
StatusText = "设置已重置";
LogManager.Info("重置设置");
}, "重置设置");
}
private void ExecuteImportConfig()
{
SafeExecute(() =>
{
// TODO: 实现配置导入功能
StatusText = "配置导入完成";
LogManager.Info("导入配置");
}, "导入配置");
}
private void ExecuteCheckUpdate()
{
SafeExecute(() =>
{
StatusText = "正在检查更新...";
// 模拟检查更新
System.Threading.Tasks.Task.Run(() =>
{
System.Threading.Thread.Sleep(2000);
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
StatusText = "当前版本已是最新版本";
}
catch (Exception ex)
{
LogManager.Error($"更新检查UI更新失败: {ex.Message}");
}
}), System.Windows.Threading.DispatcherPriority.Background);
});
LogManager.Info("检查更新");
}, "检查更新");
}
private void ExecuteGeneratePerformanceReport()
{
SafeExecute(() =>
{
StatusText = "正在生成性能报告...";
// 模拟生成报告
System.Threading.Tasks.Task.Run(() =>
{
System.Threading.Thread.Sleep(1500);
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
StatusText = "性能报告生成完成";
PerformanceInfo = $"报告已生成 - {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
}
catch (Exception ex)
{
LogManager.Error($"性能报告UI更新失败: {ex.Message}");
}
}), System.Windows.Threading.DispatcherPriority.Background);
});
LogManager.Info("生成性能报告");
}, "生成性能报告");
}
/// <summary>
/// 异步设置物流属性命令使用UIStateManager和Command Pattern
@ -1267,18 +932,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
#region
private async Task ExecuteModelSplitterAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteViewLogAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteClearLogAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteExportLogAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteOpenSettingsAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteResetSettingsAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteImportConfigAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteCheckUpdateAsync() { await Task.CompletedTask; /* TODO */ }
private async Task ExecuteGeneratePerformanceReportAsync() { await Task.CompletedTask; /* TODO */ }
#endregion
#region
/// <summary>

View File

@ -310,6 +310,21 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
AutoPathStatus = "正在创建新路径...";
// 清除所有现有路径的可视化显示
if (PathPointRenderPlugin.Instance != null)
{
try
{
PathPointRenderPlugin.Instance.ClearAllPaths();
LogManager.Info("新建路径:已清除所有现有路径可视化显示");
}
catch (Exception ex)
{
LogManager.Error($"新建路径:清除现有路径可视化失败: {ex.Message}", ex);
throw; // 重新抛出异常,让上层处理
}
}
if (_pathPlanningManager != null)
{
var newRoute = _pathPlanningManager.StartCreatingNewRoute();
@ -372,32 +387,36 @@ namespace NavisworksTransport.UI.WPF.ViewModels
var pathName = SelectedPathRoute.Name;
AutoPathStatus = $"正在删除路径: {pathName}...";
// 清理对应的3D可视化标记
// 清理当前路径的3D可视化显示使用新的统一API
if (PathPointRenderPlugin.Instance != null)
{
if (pathName.StartsWith("自动路径_"))
try
{
// 清除所有自动路径标记
var allMarkers = PathPointRenderPlugin.Instance.GetAllMarkers();
var autoPathMarkers = allMarkers.Where(m => m.SequenceNumber < -999).ToList();
foreach (var marker in autoPathMarkers)
// 使用路径名找到对应的Core路径获取其ID进行精确清理
string pathIdToRemove = null;
if (_pathPlanningManager != null)
{
PathPointRenderPlugin.Instance.RemoveMarkerAt(marker.Center, 1.0);
}
}
else
{
// 对于手动路径,清除对应序号的标记
if (SelectedPathRoute.Points.Count > 0)
{
foreach (var point in SelectedPathRoute.Points)
var coreRoute = _pathPlanningManager.Routes.FirstOrDefault(r => r.Name == pathName);
if (coreRoute != null)
{
var pointLocation = new Point3D(point.X, point.Y, point.Z);
PathPointRenderPlugin.Instance.RemoveMarkerAt(pointLocation, 2.0);
pathIdToRemove = coreRoute.Id;
LogManager.Info($"删除路径找到Core路径ID: {pathIdToRemove}");
// 使用新的API精确删除该路径
PathPointRenderPlugin.Instance.RemovePath(pathIdToRemove);
LogManager.Info($"删除路径:已清除路径 {pathName} (ID: {pathIdToRemove}) 的可视化显示");
}
else
{
LogManager.Warning($"删除路径:未找到路径 {pathName} 对应的Core路径无法清理可视化");
}
}
}
catch (Exception ex)
{
LogManager.Error($"删除路径:清除路径可视化失败: {ex.Message}", ex);
throw; // 重新抛出异常,让上层处理
}
}
// 通知PathPlanningManager删除对应的路径
@ -506,6 +525,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
AutoPathStatus = "正在计算最优路径...";
LogManager.Info("=== 开始执行自动路径规划 ===");
// 确保在开始自动路径规划前清理任何残留的事件订阅
LogManager.WriteLog("[自动路径规划] 规划前清理事件订阅状态");
CleanupAutoPathEventSubscriptions();
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
// 调用PathPlanningManager的自动路径规划功能
var startPathPoint = new PathPoint
{
@ -533,6 +560,14 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
LogManager.Info($"路径规划成功,共 {pathRoute.Points.Count} 个点");
// 自动路径规划完成后,执行完整的事件订阅清理
LogManager.WriteLog("[自动路径规划] 规划完成后清理事件订阅状态");
CleanupAutoPathEventSubscriptions();
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
// 不在这里直接操作UI让RouteGenerated事件处理UI更新
// 这避免了重复的路径添加和UI更新冲突
@ -543,6 +578,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
AutoPathStatus = "❌ 路径规划失败,未找到可行路径";
LogManager.Warning("自动路径规划失败:未找到可行路径");
// 失败情况下也要清理事件订阅
CleanupAutoPathEventSubscriptions();
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
}
}, "自动路径规划");
}
@ -561,35 +603,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
}
// 清除3D标记
// 清除所有路径可视化使用新的统一API
if (PathPointRenderPlugin.Instance != null)
{
if (_hasStartPoint)
{
PathPointRenderPlugin.Instance.RemoveMarkerAt(_startPoint3D, 2.0);
}
if (_hasEndPoint)
{
PathPointRenderPlugin.Instance.RemoveMarkerAt(_endPoint3D, 2.0);
}
// 清除自动路径规划生成的所有中间路径点标记(序号为-1000及以下
try
{
var allMarkers = PathPointRenderPlugin.Instance.GetAllMarkers();
var autoPathMarkers = allMarkers.Where(m => m.SequenceNumber <= -1000).ToList();
LogManager.Info($"找到 {autoPathMarkers.Count} 个自动路径标记需要清除");
foreach (var marker in autoPathMarkers)
{
PathPointRenderPlugin.Instance.RemoveMarkerAt(marker.Center, 1.0);
LogManager.Info($"已清除自动路径标记: 序号{marker.SequenceNumber}, 位置({marker.Center.X:F2}, {marker.Center.Y:F2}, {marker.Center.Z:F2})");
}
PathPointRenderPlugin.Instance.ClearAllPaths();
LogManager.Info("重置参数:已清除所有路径可视化显示");
}
catch (Exception ex)
{
LogManager.Warning($"清除自动路径标记时出现异常: {ex.Message}");
LogManager.Error($"重置参数:清除路径可视化失败: {ex.Message}", ex);
throw; // 重新抛出异常,让上层处理
}
}
@ -777,49 +802,61 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
try
{
if (pickResult == null) return;
LogManager.WriteLog("[自动路径事件] ===== OnAutoPathMouseClicked被调用 =====");
if (pickResult == null)
{
LogManager.WriteLog("[自动路径事件] pickResult为null退出处理");
return;
}
var point3D = pickResult.Point;
LogManager.Info($"接收到点击事件: ({point3D.X:F2}, {point3D.Y:F2}, {point3D.Z:F2})");
LogManager.WriteLog($"[自动路径事件] 接收到点击事件: ({point3D.X:F2}, {point3D.Y:F2}, {point3D.Z:F2})");
LogManager.WriteLog($"[自动路径事件] IsSelectingStartPoint: {IsSelectingStartPoint}, IsSelectingEndPoint: {IsSelectingEndPoint}");
if (IsSelectingStartPoint)
{
LogManager.WriteLog("[自动路径事件] 设置起点并停止点击工具");
SetAutoPathStartPoint(point3D);
await SafeExecuteAsync(() =>
{
_pathPlanningManager.StopClickTool();
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
CleanupAutoPathEventSubscriptions();
_pathPlanningManager?.StopClickTool();
}, "停止起点选择工具");
}
else if (IsSelectingEndPoint)
{
LogManager.WriteLog("[自动路径事件] 设置终点并停止点击工具");
SetAutoPathEndPoint(point3D);
await SafeExecuteAsync(() =>
{
_pathPlanningManager.StopClickTool();
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
CleanupAutoPathEventSubscriptions();
_pathPlanningManager?.StopClickTool();
}, "停止终点选择工具");
}
else
{
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
LogManager.WriteLog("[自动路径事件] 非选择状态,直接清理事件订阅");
CleanupAutoPathEventSubscriptions();
}
}
catch (Exception ex)
{
LogManager.Error($"处理自动路径规划点击事件时发生错误: {ex.Message}");
LogManager.Error($"[自动路径事件] 处理点击事件异常: {ex.Message}");
AutoPathStatus = $"获取点击位置失败: {ex.Message}";
IsSelectingStartPoint = false;
IsSelectingEndPoint = false;
if (_pathPlanningManager != null)
// 异常情况下也要清理事件订阅
try
{
await SafeExecuteAsync(() =>
{
_pathPlanningManager.StopClickTool();
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
}, "清理点击工具状态");
CleanupAutoPathEventSubscriptions();
_pathPlanningManager?.StopClickTool();
}
catch (Exception cleanupEx)
{
LogManager.Error($"[自动路径事件] 清理异常: {cleanupEx.Message}");
}
}
}
@ -920,6 +957,52 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
/// <summary>
/// 清理自动路径相关的事件订阅
/// </summary>
private void CleanupAutoPathEventSubscriptions()
{
try
{
LogManager.WriteLog("[事件清理] 开始清理自动路径事件订阅");
// 移除所有可能的OnAutoPathMouseClicked订阅
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
// 使用反射检查并清理重复订阅
var mouseClickedEvent = typeof(PathClickToolPlugin).GetEvent("MouseClicked");
if (mouseClickedEvent != null)
{
var eventField = typeof(PathClickToolPlugin).GetField("MouseClicked",
System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
if (eventField != null)
{
var currentDelegate = (MulticastDelegate)eventField.GetValue(null);
if (currentDelegate != null)
{
var invocationList = currentDelegate.GetInvocationList();
LogManager.WriteLog($"[事件清理] 发现 {invocationList.Length} 个事件订阅者");
foreach (var handler in invocationList)
{
if (handler.Target == this && handler.Method.Name == "OnAutoPathMouseClicked")
{
PathClickToolPlugin.MouseClicked -= (EventHandler<PickItemResult>)handler;
LogManager.WriteLog($"[事件清理] 移除了PathEditingViewModel.OnAutoPathMouseClicked订阅");
}
}
}
}
}
LogManager.WriteLog("[事件清理] 自动路径事件订阅清理完成");
}
catch (Exception ex)
{
LogManager.Error($"[事件清理] 清理自动路径事件订阅失败: {ex.Message}");
}
}
#endregion
#region PathPlanningManager事件处理
@ -1318,14 +1401,27 @@ namespace NavisworksTransport.UI.WPF.ViewModels
// 取消事件订阅
UnsubscribeFromPathPlanningManager();
// 清理自动路径规划相关的事件订阅
// 完整清理自动路径规划相关的事件订阅
try
{
PathClickToolPlugin.MouseClicked -= OnAutoPathMouseClicked;
CleanupAutoPathEventSubscriptions();
}
catch (Exception ex)
{
LogManager.Warning($"取消PathClickToolPlugin.MouseClicked事件订阅时发生异常: {ex.Message}");
LogManager.Warning($"清理自动路径事件订阅时发生异常: {ex.Message}");
}
// 确保停止任何活动的点击工具
try
{
if (_pathPlanningManager != null)
{
_pathPlanningManager.StopClickTool();
}
}
catch (Exception ex)
{
LogManager.Warning($"停止点击工具时发生异常: {ex.Message}");
}
LogManager.Info("PathEditingViewModel资源清理完成");

View File

@ -0,0 +1,534 @@
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows.Input;
using NavisworksTransport.UI.WPF.ViewModels;
using NavisworksTransport.UI.WPF.Collections;
using NavisworksTransport.Core;
using NavisworksTransport.Utils;
using NavisworksTransport.Commands;
namespace NavisworksTransport.UI.WPF.ViewModels
{
/// <summary>
/// 系统管理ViewModel - 处理插件系统管理功能
/// </summary>
public class SystemManagementViewModel : ViewModelBase
{
#region
private readonly UIStateManager _uiStateManager;
// 系统管理相关字段
private bool _isAutoSaveEnabled = true;
private bool _isDebugModeEnabled = false;
private ObservableCollection<string> _logLevels;
private string _selectedLogLevel = "Info";
private string _logStatus = "日志系统正常";
private string _pluginVersion = "v1.0";
private string _navisworksVersion = "2026";
private string _settingsStatus = "设置已加载";
private string _systemStatus = "正常";
private string _systemStatusColor = "Green";
private string _memoryUsage = "0 MB";
private string _runningTime = "00:00:00";
private string _performanceInfo = "性能监控就绪";
#endregion
#region
/// <summary>
/// 是否启用自动保存
/// </summary>
public bool IsAutoSaveEnabled
{
get => _isAutoSaveEnabled;
set => SetProperty(ref _isAutoSaveEnabled, value);
}
/// <summary>
/// 是否启用调试模式
/// </summary>
public bool IsDebugModeEnabled
{
get => _isDebugModeEnabled;
set => SetProperty(ref _isDebugModeEnabled, value);
}
/// <summary>
/// 日志级别集合
/// </summary>
public ObservableCollection<string> LogLevels
{
get => _logLevels;
set => SetProperty(ref _logLevels, value);
}
/// <summary>
/// 选中的日志级别
/// </summary>
public string SelectedLogLevel
{
get => _selectedLogLevel;
set => SetProperty(ref _selectedLogLevel, value);
}
/// <summary>
/// 日志状态
/// </summary>
public string LogStatus
{
get => _logStatus;
set => SetProperty(ref _logStatus, value);
}
/// <summary>
/// 插件版本
/// </summary>
public string PluginVersion
{
get => _pluginVersion;
set => SetProperty(ref _pluginVersion, value);
}
/// <summary>
/// Navisworks版本
/// </summary>
public string NavisworksVersion
{
get => _navisworksVersion;
set => SetProperty(ref _navisworksVersion, value);
}
/// <summary>
/// 设置状态
/// </summary>
public string SettingsStatus
{
get => _settingsStatus;
set => SetProperty(ref _settingsStatus, value);
}
/// <summary>
/// 系统状态
/// </summary>
public string SystemStatus
{
get => _systemStatus;
set => SetProperty(ref _systemStatus, value);
}
/// <summary>
/// 系统状态颜色
/// </summary>
public string SystemStatusColor
{
get => _systemStatusColor;
set => SetProperty(ref _systemStatusColor, value);
}
/// <summary>
/// 内存使用情况
/// </summary>
public string MemoryUsage
{
get => _memoryUsage;
set => SetProperty(ref _memoryUsage, value);
}
/// <summary>
/// 运行时间
/// </summary>
public string RunningTime
{
get => _runningTime;
set => SetProperty(ref _runningTime, value);
}
/// <summary>
/// 性能信息
/// </summary>
public string PerformanceInfo
{
get => _performanceInfo;
set => SetProperty(ref _performanceInfo, value);
}
#endregion
#region
public ICommand ClearLogCommand { get; private set; }
public ICommand ExportLogCommand { get; private set; }
public ICommand ViewLogCommand { get; private set; }
public ICommand OpenSettingsCommand { get; private set; }
public ICommand ResetSettingsCommand { get; private set; }
public ICommand ImportConfigCommand { get; private set; }
public ICommand CheckUpdateCommand { get; private set; }
public ICommand GeneratePerformanceReportCommand { get; private set; }
#endregion
#region
public SystemManagementViewModel() : base()
{
try
{
// 获取UI状态管理器实例
_uiStateManager = UIStateManager.Instance;
// 验证关键组件是否正常初始化
if (_uiStateManager == null)
{
LogManager.Error("UIStateManager初始化失败");
throw new InvalidOperationException("UIStateManager初始化失败");
}
// 初始化线程安全的集合
LogLevels = new ThreadSafeObservableCollection<string>();
// 初始化命令
InitializeCommands();
// 初始化系统管理设置
InitializeSystemManagementSettingsAsync();
LogManager.Info("SystemManagementViewModel构造函数执行完成");
}
catch (Exception ex)
{
LogManager.Error($"SystemManagementViewModel构造函数异常: {ex.Message}", ex);
// 在构造函数中尽量保证对象处于可用状态
SystemStatus = "初始化失败,请检查日志";
throw;
}
}
#endregion
#region
/// <summary>
/// 初始化命令
/// </summary>
private void InitializeCommands()
{
try
{
// 系统管理命令
ViewLogCommand = new RelayCommand(() => ExecuteViewLog());
ClearLogCommand = new RelayCommand(() => ExecuteClearLog());
ExportLogCommand = new RelayCommand(() => ExecuteExportLog());
OpenSettingsCommand = new RelayCommand(() => ExecuteOpenSettings());
ResetSettingsCommand = new RelayCommand(() => ExecuteResetSettings());
ImportConfigCommand = new RelayCommand(() => ExecuteImportConfig());
CheckUpdateCommand = new RelayCommand(() => ExecuteCheckUpdate());
GeneratePerformanceReportCommand = new RelayCommand(() => ExecuteGeneratePerformanceReport());
LogManager.Info("系统管理命令初始化完成");
}
catch (Exception ex)
{
LogManager.Error($"初始化命令失败: {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 初始化系统管理设置
/// </summary>
private async Task InitializeSystemManagementSettingsAsync()
{
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
// 初始化日志级别
LogLevels.Clear();
var logLevels = new[] { "Debug", "Info", "Warning", "Error" };
foreach (var level in logLevels)
{
LogLevels.Add(level);
}
SelectedLogLevel = "Info";
// 初始化系统信息
LogStatus = "日志系统正常";
SettingsStatus = "设置已加载";
PluginVersion = "v1.0";
NavisworksVersion = "2026";
SystemStatus = "正常";
SystemStatusColor = "Green";
});
// 启动性能监控
StartPerformanceMonitoring();
LogManager.Info("系统管理设置初始化完成");
}, "初始化系统管理设置");
}
/// <summary>
/// 启动性能监控
/// </summary>
private void StartPerformanceMonitoring()
{
var startTime = DateTime.Now;
// 使用定时器更新性能信息
var timer = new System.Windows.Threading.DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(5);
timer.Tick += (s, e) =>
{
try
{
// 更新内存使用
var process = System.Diagnostics.Process.GetCurrentProcess();
var memoryMB = process.WorkingSet64 / (1024 * 1024);
MemoryUsage = $"{memoryMB} MB";
// 更新运行时间
var runTime = DateTime.Now - startTime;
RunningTime = $"{runTime.Hours:D2}:{runTime.Minutes:D2}:{runTime.Seconds:D2}";
// 更新性能信息
PerformanceInfo = $"CPU: 正常, 内存: {memoryMB}MB, 运行时间: {RunningTime}";
}
catch (Exception ex)
{
LogManager.Error($"性能监控更新失败: {ex.Message}");
}
};
timer.Start();
}
#endregion
#region
/// <summary>
/// 查看日志
/// </summary>
private void ExecuteViewLog()
{
SafeExecute(() =>
{
// TODO: 实现日志查看功能
LogStatus = "打开日志查看器";
LogManager.Info("查看日志");
}, "查看日志");
}
/// <summary>
/// 清空日志
/// </summary>
private void ExecuteClearLog()
{
SafeExecute(() =>
{
// TODO: 实现日志清空功能
LogStatus = "日志已清空";
LogManager.Info("清空日志");
}, "清空日志");
}
/// <summary>
/// 导出日志
/// </summary>
private void ExecuteExportLog()
{
SafeExecute(() =>
{
// TODO: 实现日志导出功能
LogStatus = "日志导出完成";
LogManager.Info("导出日志");
}, "导出日志");
}
/// <summary>
/// 打开设置
/// </summary>
private void ExecuteOpenSettings()
{
SafeExecute(() =>
{
// TODO: 实现设置对话框
SettingsStatus = "打开插件设置";
LogManager.Info("打开设置");
}, "打开设置");
}
/// <summary>
/// 重置设置
/// </summary>
private void ExecuteResetSettings()
{
SafeExecute(() =>
{
// TODO: 实现设置重置功能
SettingsStatus = "设置已重置为默认值";
IsAutoSaveEnabled = true;
IsDebugModeEnabled = false;
LogManager.Info("重置设置");
}, "重置设置");
}
/// <summary>
/// 导入配置
/// </summary>
private void ExecuteImportConfig()
{
SafeExecute(() =>
{
// TODO: 实现配置导入功能
SettingsStatus = "配置导入完成";
LogManager.Info("导入配置");
}, "导入配置");
}
/// <summary>
/// 检查更新
/// </summary>
private void ExecuteCheckUpdate()
{
SafeExecute(() =>
{
SystemStatus = "正在检查更新...";
// 模拟检查更新
System.Threading.Tasks.Task.Run(() =>
{
System.Threading.Thread.Sleep(2000);
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
SystemStatus = "当前版本已是最新版本";
}
catch (Exception ex)
{
LogManager.Error($"更新检查UI更新失败: {ex.Message}");
}
}), System.Windows.Threading.DispatcherPriority.Background);
});
LogManager.Info("检查更新");
}, "检查更新");
}
/// <summary>
/// 生成性能报告
/// </summary>
private void ExecuteGeneratePerformanceReport()
{
SafeExecute(() =>
{
SystemStatus = "正在生成性能报告...";
// 模拟生成报告
System.Threading.Tasks.Task.Run(() =>
{
System.Threading.Thread.Sleep(1500);
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
SystemStatus = "性能报告生成完成";
PerformanceInfo = $"报告已生成 - {DateTime.Now:yyyy-MM-dd HH:mm:ss}";
}
catch (Exception ex)
{
LogManager.Error($"性能报告UI更新失败: {ex.Message}");
}
}), System.Windows.Threading.DispatcherPriority.Background);
});
LogManager.Info("生成性能报告");
}, "生成性能报告");
}
#endregion
#region
/// <summary>
/// 安全执行异步操作
/// </summary>
private async Task SafeExecuteAsync(Func<Task> action, string operationName = "未知操作")
{
try
{
await action();
}
catch (Exception ex)
{
LogManager.Error($"{operationName}发生异常: {ex.Message}", ex);
SystemStatus = $"{operationName}失败: {ex.Message}";
}
}
/// <summary>
/// 安全执行同步操作
/// </summary>
private void SafeExecute(Action action, string operationName = "未知操作")
{
try
{
action();
}
catch (Exception ex)
{
LogManager.Error($"{operationName}发生异常: {ex.Message}", ex);
SystemStatus = $"{operationName}失败: {ex.Message}";
}
}
/// <summary>
/// 验证ViewModel状态是否正常
/// </summary>
public bool IsValidState()
{
return _uiStateManager != null &&
LogLevels != null;
}
/// <summary>
/// 获取ViewModel状态信息
/// </summary>
public string GetStateInfo()
{
return $"UIStateManager: {(_uiStateManager != null ? "" : "")}, " +
$"日志级别数量: {LogLevels?.Count ?? 0}, " +
$"系统状态: {SystemStatus}";
}
#endregion
#region
public void Cleanup()
{
try
{
LogManager.Info("开始清理SystemManagementViewModel资源");
// 目前没有需要特别清理的资源
LogManager.Info("SystemManagementViewModel资源清理完成");
}
catch (Exception ex)
{
LogManager.Error($"SystemManagementViewModel清理失败: {ex.Message}");
}
}
#endregion
}
}

View File

@ -1,56 +1,159 @@
<!--
NavisworksTransport 系统管理页签视图 - 采用与其他页签一致的Navisworks 2026风格
功能说明:
1. 日志管理:查看、清空、导出日志,设置日志级别
2. 插件设置:设置选项、重置设置、导入配置、启用选项
3. 系统信息插件版本、Navisworks版本、系统状态、内存使用、运行时间
4. 性能监控:性能信息和性能报告生成
设计原则与Navisworks 2026风格一致480像素宽度现代化UI布局采用Border分组
-->
<UserControl x:Class="NavisworksTransport.UI.WPF.Views.SystemManagementView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="400">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel Margin="10">
<GroupBox Header="模型分层拆分" Margin="0,10" Height="120">
<StackPanel Margin="10">
<Button Content="模型分层拆分" Command="{Binding ModelSplitterCommand}"
Margin="0,0,0,10" HorizontalAlignment="Left"/>
<Label Content="将大型模型按楼层或属性拆分为多个文件"
Foreground="Gray" FontSize="10"/>
<Label Content="{Binding ModelSplitterStatus}" FontSize="10" Foreground="DarkBlue"/>
d:DesignHeight="800" d:DesignWidth="480">
<UserControl.Resources>
<!-- Navisworks 2026 风格样式定义 -->
<Style x:Key="SectionHeaderStyle" TargetType="Label">
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,5,0,2"/>
</Style>
<Style x:Key="ActionButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FF4472C4"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderBrush" Value="#FF2B579A"/>
<Setter Property="Padding" Value="10,5"/>
<Setter Property="Margin" Value="0,0,10,0"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</Style>
<Style x:Key="SecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="#FFE7F1FF"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="BorderBrush" Value="#FF4472C4"/>
<Setter Property="Padding" Value="8,4"/>
<Setter Property="Margin" Value="0,0,8,0"/>
</Style>
<Style x:Key="StatusTextStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
</Style>
<Style x:Key="InfoTextStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="Foreground" Value="#FF666666"/>
<Setter Property="Padding" Value="0,2"/>
</Style>
<Style x:Key="ParameterLabelStyle" TargetType="Label">
<Setter Property="Width" Value="80"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Padding" Value="0,0,5,0"/>
<Setter Property="FontSize" Value="10"/>
</Style>
<Style x:Key="StatusLabelStyle" TargetType="Label">
<Setter Property="FontSize" Value="10"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="#FF2B579A"/>
<Setter Property="Padding" Value="0,2"/>
</Style>
</UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="10">
<StackPanel>
<!-- 区域1: 日志管理 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="日志管理" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 日志操作按钮 -->
<StackPanel Orientation="Horizontal" Margin="0,10,0,10">
<Button Content="查看日志"
Command="{Binding ViewLogCommand}"
Style="{StaticResource ActionButtonStyle}"/>
<Button Content="清空日志"
Command="{Binding ClearLogCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
<Button Content="导出日志"
Command="{Binding ExportLogCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
</StackPanel>
<!-- 日志级别设置 -->
<Grid Margin="0,5,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="日志级别:" Style="{StaticResource ParameterLabelStyle}" Width="60"/>
<ComboBox Grid.Column="1"
ItemsSource="{Binding LogLevels}"
SelectedItem="{Binding SelectedLogLevel}"
Width="100"
Margin="5,0,0,0"/>
</Grid>
<!-- 状态显示 -->
<Label Content="{Binding LogStatus}"
Style="{StaticResource StatusLabelStyle}"
Foreground="#FF2B8A2B"/>
</StackPanel>
</GroupBox>
</Border>
<GroupBox Header="日志管理" Margin="0,10" Height="140">
<StackPanel Margin="10">
<!-- 区域2: 插件设置 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="插件设置" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 设置操作按钮 -->
<StackPanel Orientation="Horizontal" Margin="0,10,0,10">
<Button Content="设置选项"
Command="{Binding OpenSettingsCommand}"
Style="{StaticResource ActionButtonStyle}"/>
<Button Content="重置设置"
Command="{Binding ResetSettingsCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
<Button Content="导入配置"
Command="{Binding ImportConfigCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
</StackPanel>
<!-- 选项设置 -->
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<Button Content="查看日志" Command="{Binding ViewLogCommand}" Margin="0,0,10,0"/>
<Button Content="清空日志" Command="{Binding ClearLogCommand}" Margin="0,0,10,0"/>
<Button Content="导出日志" Command="{Binding ExportLogCommand}"/>
<CheckBox Content="启用自动保存"
IsChecked="{Binding IsAutoSaveEnabled}"
Margin="0,0,20,0"
VerticalAlignment="Center"/>
<CheckBox Content="启用调试模式"
IsChecked="{Binding IsDebugModeEnabled}"
VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,5">
<Label Content="日志级别:" Width="60"/>
<ComboBox ItemsSource="{Binding LogLevels}"
SelectedItem="{Binding SelectedLogLevel}" Width="100"/>
</StackPanel>
<Label Content="{Binding LogStatus}" FontSize="10" Foreground="DarkGreen"/>
<!-- 状态显示 -->
<Label Content="{Binding SettingsStatus}"
Style="{StaticResource StatusLabelStyle}"/>
</StackPanel>
</GroupBox>
</Border>
<GroupBox Header="插件设置" Margin="0,10" Height="140">
<StackPanel Margin="10">
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<Button Content="设置选项" Command="{Binding OpenSettingsCommand}" Margin="0,0,10,0"/>
<Button Content="重置设置" Command="{Binding ResetSettingsCommand}" Margin="0,0,10,0"/>
<Button Content="导入配置" Command="{Binding ImportConfigCommand}"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,0,0,5">
<CheckBox Content="启用自动保存" IsChecked="{Binding IsAutoSaveEnabled}" Margin="0,0,15,0"/>
<CheckBox Content="启用调试模式" IsChecked="{Binding IsDebugModeEnabled}"/>
</StackPanel>
<Label Content="{Binding SettingsStatus}" FontSize="10" Foreground="DarkBlue"/>
</StackPanel>
</GroupBox>
<GroupBox Header="系统信息" Margin="0,10" Height="180">
<StackPanel Margin="10">
<Grid>
<!-- 区域3: 系统信息 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,15" Padding="12">
<StackPanel>
<Label Content="系统信息" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 系统信息表格 -->
<Grid Margin="0,10,0,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
@ -63,34 +166,53 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="插件版本:" FontSize="10"/>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding PluginVersion}" FontSize="10"/>
<Label Grid.Row="0" Grid.Column="0" Content="插件版本:" Style="{StaticResource ParameterLabelStyle}" Width="100"/>
<Label Grid.Row="0" Grid.Column="1" Content="{Binding PluginVersion}" Style="{StaticResource InfoTextStyle}"/>
<Label Grid.Row="1" Grid.Column="0" Content="Navisworks版本:" FontSize="10"/>
<Label Grid.Row="1" Grid.Column="1" Content="{Binding NavisworksVersion}" FontSize="10"/>
<Label Grid.Row="1" Grid.Column="0" Content="Navisworks版本:" Style="{StaticResource ParameterLabelStyle}" Width="100"/>
<Label Grid.Row="1" Grid.Column="1" Content="{Binding NavisworksVersion}" Style="{StaticResource InfoTextStyle}"/>
<Label Grid.Row="2" Grid.Column="0" Content="系统状态:" FontSize="10"/>
<Label Grid.Row="2" Grid.Column="1" Content="{Binding SystemStatus}" FontSize="10"
<Label Grid.Row="2" Grid.Column="0" Content="系统状态:" Style="{StaticResource ParameterLabelStyle}" Width="100"/>
<Label Grid.Row="2" Grid.Column="1" Content="{Binding SystemStatus}"
Style="{StaticResource InfoTextStyle}"
Foreground="{Binding SystemStatusColor}"/>
<Label Grid.Row="3" Grid.Column="0" Content="内存使用:" FontSize="10"/>
<Label Grid.Row="3" Grid.Column="1" Content="{Binding MemoryUsage}" FontSize="10"/>
<Label Grid.Row="3" Grid.Column="0" Content="内存使用:" Style="{StaticResource ParameterLabelStyle}" Width="100"/>
<Label Grid.Row="3" Grid.Column="1" Content="{Binding MemoryUsage}" Style="{StaticResource InfoTextStyle}"/>
<Label Grid.Row="4" Grid.Column="0" Content="运行时间:" FontSize="10"/>
<Label Grid.Row="4" Grid.Column="1" Content="{Binding RunningTime}" FontSize="10"/>
<Label Grid.Row="4" Grid.Column="0" Content="运行时间:" Style="{StaticResource ParameterLabelStyle}" Width="100"/>
<Label Grid.Row="4" Grid.Column="1" Content="{Binding RunningTime}" Style="{StaticResource InfoTextStyle}"/>
</Grid>
<Button Content="检查更新" Command="{Binding CheckUpdateCommand}"
Margin="0,10,0,0" HorizontalAlignment="Left"/>
<!-- 更新检查按钮 -->
<StackPanel Orientation="Horizontal">
<Button Content="检查更新"
Command="{Binding CheckUpdateCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
</StackPanel>
</StackPanel>
</GroupBox>
</Border>
<GroupBox Header="性能监控" Margin="0,10">
<StackPanel Margin="10">
<Label Content="{Binding PerformanceInfo}" FontSize="10" Foreground="Gray"/>
<Button Content="生成性能报告" Command="{Binding GeneratePerformanceReportCommand}"
HorizontalAlignment="Left" Margin="0,5,0,0"/>
<!-- 区域4: 性能监控 -->
<Border BorderBrush="#FFD4E7FF" BorderThickness="1" CornerRadius="4" Margin="0,0,0,0" Padding="12">
<StackPanel>
<Label Content="性能监控" Style="{StaticResource SectionHeaderStyle}"/>
<!-- 性能信息显示 -->
<TextBlock Text="{Binding PerformanceInfo}"
FontSize="10"
Foreground="#FF666666"
Margin="0,10,0,15"
TextWrapping="Wrap"/>
<!-- 报告生成按钮 -->
<StackPanel Orientation="Horizontal">
<Button Content="生成性能报告"
Command="{Binding GeneratePerformanceReportCommand}"
Style="{StaticResource ActionButtonStyle}"/>
</StackPanel>
</StackPanel>
</GroupBox>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl>