581 lines
22 KiB
C#
581 lines
22 KiB
C#
using System;
|
||
using System.Collections.Concurrent;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using NavisworksTransport.Core;
|
||
|
||
namespace NavisworksTransport.Commands
|
||
{
|
||
/// <summary>
|
||
/// 命令管理器
|
||
/// 提供命令注册、创建、执行的统一管理,与UIStateManager深度集成
|
||
/// </summary>
|
||
public class CommandManager
|
||
{
|
||
#region 字段和属性
|
||
|
||
private static CommandManager _instance;
|
||
private static readonly object _instanceLock = new object();
|
||
|
||
private readonly ConcurrentDictionary<string, Func<IPathPlanningCommand>> _commandFactories;
|
||
private readonly CommandExecutor _commandExecutor;
|
||
private readonly UIStateManager _uiStateManager;
|
||
private volatile bool _isDisposed = false;
|
||
|
||
/// <summary>
|
||
/// 获取CommandManager的单例实例
|
||
/// </summary>
|
||
public static CommandManager Instance
|
||
{
|
||
get
|
||
{
|
||
if (_instance == null)
|
||
{
|
||
lock (_instanceLock)
|
||
{
|
||
if (_instance == null)
|
||
{
|
||
_instance = new CommandManager();
|
||
}
|
||
}
|
||
}
|
||
return _instance;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 命令执行器
|
||
/// </summary>
|
||
public CommandExecutor Executor => _commandExecutor;
|
||
|
||
#endregion
|
||
|
||
#region 事件
|
||
|
||
/// <summary>
|
||
/// 命令注册事件
|
||
/// </summary>
|
||
public event EventHandler<CommandRegistrationEventArgs> CommandRegistered;
|
||
|
||
/// <summary>
|
||
/// 命令执行开始事件
|
||
/// </summary>
|
||
public event EventHandler<CommandExecutionEventArgs> CommandExecutionStarted;
|
||
|
||
/// <summary>
|
||
/// 命令执行完成事件
|
||
/// </summary>
|
||
public event EventHandler<CommandCompletedEventArgs> CommandExecutionCompleted;
|
||
|
||
#endregion
|
||
|
||
#region 构造函数
|
||
|
||
private CommandManager()
|
||
{
|
||
_commandFactories = new ConcurrentDictionary<string, Func<IPathPlanningCommand>>();
|
||
_commandExecutor = CommandExecutor.Instance;
|
||
_uiStateManager = UIStateManager.Instance;
|
||
|
||
// 订阅CommandExecutor事件
|
||
_commandExecutor.CommandStarted += OnCommandStarted;
|
||
_commandExecutor.CommandCompleted += OnCommandCompleted;
|
||
|
||
// 注册默认命令
|
||
RegisterDefaultCommands();
|
||
|
||
LogManager.Info("CommandManager 初始化完成");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 命令注册
|
||
|
||
/// <summary>
|
||
/// 注册命令工厂
|
||
/// </summary>
|
||
public void RegisterCommand<T>(string commandKey, Func<T> factory) where T : IPathPlanningCommand
|
||
{
|
||
if (string.IsNullOrEmpty(commandKey))
|
||
throw new ArgumentException("命令键不能为空", nameof(commandKey));
|
||
|
||
if (factory == null)
|
||
throw new ArgumentNullException(nameof(factory));
|
||
|
||
_commandFactories.AddOrUpdate(commandKey, () => factory(), (key, oldFactory) => () => factory());
|
||
|
||
OnCommandRegistered(commandKey, typeof(T));
|
||
LogManager.Info($"命令已注册: {commandKey} -> {typeof(T).Name}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 注册命令工厂(带参数)
|
||
/// </summary>
|
||
public void RegisterCommand<T>(string commandKey, Func<object[], T> factory) where T : IPathPlanningCommand
|
||
{
|
||
if (string.IsNullOrEmpty(commandKey))
|
||
throw new ArgumentException("命令键不能为空", nameof(commandKey));
|
||
|
||
if (factory == null)
|
||
throw new ArgumentNullException(nameof(factory));
|
||
|
||
// 存储一个包装函数,在创建时会需要参数
|
||
_commandFactories.AddOrUpdate(commandKey,
|
||
() => throw new InvalidOperationException($"命令 {commandKey} 需要参数,请使用 CreateCommand(string, params object[]) 方法"),
|
||
(key, oldFactory) => () => throw new InvalidOperationException($"命令 {commandKey} 需要参数,请使用 CreateCommand(string, params object[]) 方法"));
|
||
|
||
// 单独存储参数化工厂
|
||
_parameterizedFactories.AddOrUpdate(commandKey, factory, (key, oldFactory) => factory);
|
||
|
||
OnCommandRegistered(commandKey, typeof(T));
|
||
LogManager.Info($"参数化命令已注册: {commandKey} -> {typeof(T).Name}");
|
||
}
|
||
|
||
private readonly ConcurrentDictionary<string, Delegate> _parameterizedFactories = new ConcurrentDictionary<string, Delegate>();
|
||
|
||
/// <summary>
|
||
/// 注册默认命令
|
||
/// </summary>
|
||
private void RegisterDefaultCommands()
|
||
{
|
||
// 注册基本路径规划命令 - 暂时移除,避免构造函数参数问题
|
||
// RegisterCommand("SelectChannels", () => new SelectChannelsCommand());
|
||
// RegisterCommand("CreatePathRoute", () => new CreatePathRouteCommand());
|
||
|
||
// 注册自动路径规划命令
|
||
RegisterCommand("AutoPathPlanning", (object[] args) =>
|
||
{
|
||
if (args.Length < 2)
|
||
throw new ArgumentException("AutoPathPlanning 需要至少起点和终点参数");
|
||
|
||
var startPoint = args[0] as Autodesk.Navisworks.Api.Point3D;
|
||
var endPoint = args[1] as Autodesk.Navisworks.Api.Point3D;
|
||
|
||
if (startPoint == null || endPoint == null)
|
||
throw new ArgumentException("起点和终点必须是 Point3D 类型");
|
||
|
||
var parameters = new AutoPathPlanningParameters
|
||
{
|
||
StartPoint = startPoint,
|
||
EndPoint = endPoint,
|
||
ObjectWidthMeters = args.Length > 2 && args[2] is double v ? v : 1.0,
|
||
SafetyMarginMeters = args.Length > 3 && args[3] is double v1 ? v1 : 0.5,
|
||
GridSizeMeters = args.Length > 4 && args[4] is double v2 ? v2 : -1,
|
||
PathName = args.Length > 5 ? args[5]?.ToString() : null,
|
||
AutoDrawVisualization = args.Length <= 6 || !(args[6] is bool v3) || v3
|
||
};
|
||
|
||
return new AutoPathPlanningCommand(parameters);
|
||
});
|
||
|
||
// 注册快捷自动路径规划命令
|
||
RegisterCommand("AutoPathPlanningQuick", (object[] args) =>
|
||
{
|
||
if (args.Length < 2)
|
||
throw new ArgumentException("AutoPathPlanningQuick 需要至少起点和终点参数");
|
||
|
||
var startPoint = args[0] as Autodesk.Navisworks.Api.Point3D;
|
||
var endPoint = args[1] as Autodesk.Navisworks.Api.Point3D;
|
||
|
||
if (startPoint == null || endPoint == null)
|
||
throw new ArgumentException("起点和终点必须是 Point3D 类型");
|
||
|
||
var objectSize = args.Length > 2 && args[2] is double v ? v : 1.0;
|
||
var pathName = args.Length > 3 ? args[3]?.ToString() : null;
|
||
|
||
return AutoPathPlanningCommand.CreateQuick(startPoint, endPoint, objectSize, pathName);
|
||
});
|
||
|
||
// 注册模拟路径规划命令(保留用于测试)- 暂时注释掉避免类型推断问题
|
||
// RegisterCommand("MockAutoPathPlanning", (object[] args) => { return null; });
|
||
|
||
// 注册新的业务Commands
|
||
RegisterNewBusinessCommands();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 注册新的业务Commands
|
||
/// </summary>
|
||
private void RegisterNewBusinessCommands()
|
||
{
|
||
LogManager.Info("开始注册新的业务Commands");
|
||
|
||
// 1. 注册设置物流属性命令
|
||
RegisterCommand("SetLogisticsAttribute", (object[] args) =>
|
||
{
|
||
if (args.Length < 2)
|
||
throw new ArgumentException("SetLogisticsAttribute 需要目标模型项和元素类型参数");
|
||
|
||
var targetItems = args[0] as Autodesk.Navisworks.Api.ModelItemCollection;
|
||
var elementType = args[1];
|
||
|
||
if (targetItems == null)
|
||
throw new ArgumentException("第一个参数必须是 ModelItemCollection 类型");
|
||
|
||
if (!Enum.TryParse<CategoryAttributeManager.LogisticsElementType>(elementType.ToString(), out var logisticsType))
|
||
throw new ArgumentException("第二个参数必须是有效的 LogisticsElementType");
|
||
|
||
var parameters = new SetLogisticsAttributeParameters
|
||
{
|
||
TargetItems = targetItems,
|
||
ElementType = logisticsType,
|
||
IsTraversable = args.Length > 2 && args[2] is bool ? (bool?)args[2] : null,
|
||
OverwriteExisting = args.Length <= 3 || !(args[3] is bool v) || v
|
||
};
|
||
|
||
return new SetLogisticsAttributeCommand(parameters);
|
||
});
|
||
|
||
// 2. 注册删除路径命令
|
||
RegisterCommand("DeletePath", (object[] args) =>
|
||
{
|
||
var parameters = new DeletePathParameters();
|
||
|
||
if (args.Length > 0)
|
||
{
|
||
if (args[0] is PathRoute route)
|
||
{
|
||
parameters.PathsToDelete.Add(route);
|
||
}
|
||
else if (args[0] is string pathId)
|
||
{
|
||
parameters.PathIds.Add(pathId);
|
||
}
|
||
else if (args[0] is bool deleteAll && deleteAll)
|
||
{
|
||
parameters.DeleteAll = true;
|
||
}
|
||
}
|
||
|
||
parameters.CreateBackup = args.Length <= 1 || !(args[1] is bool v) || v;
|
||
parameters.ForceDelete = args.Length > 2 && args[2] is bool v1 && v1;
|
||
|
||
return new DeletePathCommand(parameters);
|
||
});
|
||
|
||
// 3. 注册导入路径命令
|
||
RegisterCommand("ImportPath", (object[] args) =>
|
||
{
|
||
if (args.Length < 1)
|
||
throw new ArgumentException("ImportPath 需要文件路径参数");
|
||
|
||
var filePath = args[0]?.ToString();
|
||
if (string.IsNullOrEmpty(filePath))
|
||
throw new ArgumentException("文件路径不能为空");
|
||
|
||
var parameters = new ImportPathParameters
|
||
{
|
||
FilePath = filePath,
|
||
ImportFormat = args.Length > 1 && args[1] is ExportFormat format ? format : ExportFormat.Xml,
|
||
MergeWithExisting = args.Length <= 2 || !(args[2] is bool v) || v,
|
||
CreateBackup = args.Length <= 3 || !(args[3] is bool v1) || v1
|
||
};
|
||
|
||
return new ImportPathCommand(parameters);
|
||
});
|
||
|
||
// 4. 注册导出路径命令
|
||
RegisterCommand("ExportPath", (object[] args) =>
|
||
{
|
||
if (args.Length < 1)
|
||
throw new ArgumentException("ExportPath 需要输出文件路径参数");
|
||
|
||
var outputPath = args[0]?.ToString();
|
||
if (string.IsNullOrEmpty(outputPath))
|
||
throw new ArgumentException("输出文件路径不能为空");
|
||
|
||
var parameters = new ExportPathParameters
|
||
{
|
||
OutputFilePath = outputPath,
|
||
ExportAll = args.Length <= 1 || !(args[1] is bool v) || v,
|
||
ExportFormat = args.Length > 2 && args[2] is ExportFormat format ? format : ExportFormat.Xml,
|
||
OverwriteExisting = args.Length > 3 && args[3] is bool v1 && v1
|
||
};
|
||
|
||
return new ExportPathCommand(parameters);
|
||
});
|
||
|
||
// 5. 注册启动动画命令(原第6项)
|
||
RegisterCommand("StartAnimation", (object[] args) =>
|
||
{
|
||
if (args.Length < 1 || !(args[0] is PathRoute route))
|
||
throw new ArgumentException("StartAnimation 需要 PathRoute 参数");
|
||
|
||
var parameters = new StartAnimationParameters
|
||
{
|
||
TargetRoute = route,
|
||
AnimationSpeed = args.Length > 1 && args[1] is double v ? v : 1.0,
|
||
Loop = args.Length > 2 && args[2] is bool v1 && v1,
|
||
AutoStart = args.Length <= 3 || !(args[3] is bool v2) || v2
|
||
};
|
||
|
||
return new StartAnimationCommand(parameters);
|
||
});
|
||
|
||
LogManager.Info("新的业务Commands注册完成");
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 命令创建和执行
|
||
|
||
/// <summary>
|
||
/// 创建命令实例
|
||
/// </summary>
|
||
public IPathPlanningCommand CreateCommand(string commandKey)
|
||
{
|
||
if (!_commandFactories.TryGetValue(commandKey, out var factory))
|
||
{
|
||
throw new ArgumentException($"未注册的命令: {commandKey}");
|
||
}
|
||
|
||
try
|
||
{
|
||
return factory();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"创建命令失败: {commandKey}", ex);
|
||
throw new InvalidOperationException($"创建命令失败: {commandKey}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建命令实例(带参数)
|
||
/// </summary>
|
||
public IPathPlanningCommand CreateCommand(string commandKey, params object[] parameters)
|
||
{
|
||
if (!_parameterizedFactories.TryGetValue(commandKey, out var factory))
|
||
{
|
||
// 尝试无参数创建
|
||
return CreateCommand(commandKey);
|
||
}
|
||
|
||
try
|
||
{
|
||
return (IPathPlanningCommand)factory.DynamicInvoke(new object[] { parameters });
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"创建参数化命令失败: {commandKey}", ex);
|
||
throw new InvalidOperationException($"创建参数化命令失败: {commandKey}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行命令(异步)
|
||
/// </summary>
|
||
public async Task<PathPlanningResult> ExecuteCommandAsync(string commandKey, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var command = CreateCommand(commandKey);
|
||
return await _commandExecutor.ExecuteAsync(command, cancellationToken);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"执行命令失败: {commandKey}", ex);
|
||
return PathPlanningResult.Failure($"执行命令失败: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行命令(带参数,异步)
|
||
/// </summary>
|
||
public async Task<PathPlanningResult> ExecuteCommandAsync(string commandKey, object[] parameters, CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var command = CreateCommand(commandKey, parameters);
|
||
return await _commandExecutor.ExecuteAsync(command, cancellationToken);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"执行参数化命令失败: {commandKey}", ex);
|
||
return PathPlanningResult.Failure($"执行参数化命令失败: {ex.Message}", ex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将命令加入队列执行
|
||
/// </summary>
|
||
public Task<PathPlanningResult> EnqueueCommandAsync(string commandKey,
|
||
CommandPriority priority = CommandPriority.Normal,
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var command = CreateCommand(commandKey);
|
||
return _commandExecutor.EnqueueAsync(command, priority, cancellationToken);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"将命令加入队列失败: {commandKey}", ex);
|
||
return Task.FromResult(PathPlanningResult.Failure($"将命令加入队列失败: {ex.Message}", ex));
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将命令加入队列执行(带参数)
|
||
/// </summary>
|
||
public Task<PathPlanningResult> EnqueueCommandAsync(string commandKey,
|
||
object[] parameters,
|
||
CommandPriority priority = CommandPriority.Normal,
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
try
|
||
{
|
||
var command = CreateCommand(commandKey, parameters);
|
||
return _commandExecutor.EnqueueAsync(command, priority, cancellationToken);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"将参数化命令加入队列失败: {commandKey}", ex);
|
||
return Task.FromResult(PathPlanningResult.Failure($"将参数化命令加入队列失败: {ex.Message}", ex));
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 管理功能
|
||
|
||
/// <summary>
|
||
/// 获取已注册的命令列表
|
||
/// </summary>
|
||
public IEnumerable<string> GetRegisteredCommands()
|
||
{
|
||
return _commandFactories.Keys.ToArray();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查命令是否已注册
|
||
/// </summary>
|
||
public bool IsCommandRegistered(string commandKey)
|
||
{
|
||
return _commandFactories.ContainsKey(commandKey);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消注册命令
|
||
/// </summary>
|
||
public bool UnregisterCommand(string commandKey)
|
||
{
|
||
var removed = _commandFactories.TryRemove(commandKey, out _);
|
||
_parameterizedFactories.TryRemove(commandKey, out _);
|
||
|
||
if (removed)
|
||
{
|
||
LogManager.Info($"命令已取消注册: {commandKey}");
|
||
}
|
||
|
||
return removed;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取运行状态统计
|
||
/// </summary>
|
||
public CommandManagerStatus GetStatus()
|
||
{
|
||
return new CommandManagerStatus
|
||
{
|
||
RegisteredCommandCount = _commandFactories.Count,
|
||
RunningCommandCount = _commandExecutor.RunningCommandCount,
|
||
QueuedCommandCount = _commandExecutor.QueuedCommandCount,
|
||
RegisteredCommands = GetRegisteredCommands().ToArray(),
|
||
RunningCommands = _commandExecutor.GetRunningCommands().ToArray()
|
||
};
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 事件处理
|
||
|
||
private void OnCommandStarted(object sender, CommandExecutionEventArgs e)
|
||
{
|
||
// 使用UIStateManager安全地更新UI
|
||
_uiStateManager.QueueUIUpdate(() =>
|
||
{
|
||
CommandExecutionStarted?.Invoke(this, e);
|
||
}, UIUpdatePriority.Normal);
|
||
}
|
||
|
||
private void OnCommandCompleted(object sender, CommandCompletedEventArgs e)
|
||
{
|
||
// 使用UIStateManager安全地更新UI
|
||
_uiStateManager.QueueUIUpdate(() =>
|
||
{
|
||
CommandExecutionCompleted?.Invoke(this, e);
|
||
}, UIUpdatePriority.Normal);
|
||
}
|
||
|
||
private void OnCommandRegistered(string commandKey, Type commandType)
|
||
{
|
||
try
|
||
{
|
||
CommandRegistered?.Invoke(this, new CommandRegistrationEventArgs(commandKey, commandType));
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error("触发命令注册事件时出现异常", ex);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 资源清理
|
||
|
||
/// <summary>
|
||
/// 释放资源
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
if (_isDisposed) return;
|
||
|
||
_isDisposed = true;
|
||
|
||
// 取消订阅事件
|
||
_commandExecutor.CommandStarted -= OnCommandStarted;
|
||
_commandExecutor.CommandCompleted -= OnCommandCompleted;
|
||
|
||
// 释放CommandExecutor
|
||
_commandExecutor?.Dispose();
|
||
|
||
LogManager.Info("CommandManager 已释放");
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
|
||
#region 辅助类
|
||
|
||
/// <summary>
|
||
/// 命令管理器状态
|
||
/// </summary>
|
||
public class CommandManagerStatus
|
||
{
|
||
public int RegisteredCommandCount { get; set; }
|
||
public int RunningCommandCount { get; set; }
|
||
public int QueuedCommandCount { get; set; }
|
||
public string[] RegisteredCommands { get; set; }
|
||
public CommandInfo[] RunningCommands { get; set; }
|
||
}
|
||
|
||
/// <summary>
|
||
/// 命令注册事件参数
|
||
/// </summary>
|
||
public class CommandRegistrationEventArgs : EventArgs
|
||
{
|
||
public string CommandKey { get; }
|
||
public Type CommandType { get; }
|
||
|
||
public CommandRegistrationEventArgs(string commandKey, Type commandType)
|
||
{
|
||
CommandKey = commandKey;
|
||
CommandType = commandType;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
} |