807 lines
29 KiB
C#
807 lines
29 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using System.Windows.Forms;
|
||
using LessokajiWeaverUtilities.MagicAttributes;
|
||
using LessokajiWeaverUtilities.Utilities;
|
||
using SimpleLite;
|
||
using SimpleLite.RCS;
|
||
using SimpleLite.RCS.CarTypes;
|
||
using SimpleCore;
|
||
using SimpleCore.Library;
|
||
using StandardScene;
|
||
using StandardScene.Utils;
|
||
|
||
namespace StandardScene.ExtendDevice.ButtonBox
|
||
{
|
||
[MissionType(Name = "按钮进程")]
|
||
[I18N.DocumentTranslation(Name = "ButtonMission",locale = "en")]
|
||
public class ButtonMission:Mission
|
||
{
|
||
private const string DataFileName = "ButtonBoxConfig.json";
|
||
private string _dataFilePath;
|
||
|
||
/// <summary>
|
||
/// 当前所有按钮盒实例列表
|
||
/// </summary>
|
||
private List<BasicButtonBox> _buttonBoxes = new List<BasicButtonBox>();
|
||
|
||
/// <summary>
|
||
/// 用于管理异步循环的取消令牌源
|
||
/// </summary>
|
||
private CancellationTokenSource _cancellationTokenSource;
|
||
|
||
/// <summary>
|
||
/// 保存监控配置与状态的后台任务,便于关闭时等待
|
||
/// </summary>
|
||
private Task _configTask;
|
||
|
||
private Task _stateTask;
|
||
|
||
/// <summary>
|
||
/// 同步锁,用于保护按钮盒列表的并发访问
|
||
/// </summary>
|
||
private readonly object _syncLock = new object();
|
||
|
||
[MethodMember(Name = "启动进程")]
|
||
[I18N.DocumentTranslation(Name = "Start Mission", locale = "en")]
|
||
public override void Execute()
|
||
{
|
||
// 设置数据文件路径
|
||
_dataFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DataFileName);
|
||
|
||
// 如果已经启动,先停止之前的循环
|
||
StopInternalAsync().GetAwaiter().GetResult();
|
||
|
||
// 创建新的取消令牌源
|
||
_cancellationTokenSource = new CancellationTokenSource();
|
||
|
||
// 启动异步循环
|
||
var token = _cancellationTokenSource.Token;
|
||
_configTask = Task.Run(async () => await MonitorButtonBoxConfigAsync(token), token);
|
||
_stateTask = Task.Run(async () => await MonitorButtonStatesAsync(token), token);
|
||
status.status = "Running";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 异步监控按钮盒配置文件
|
||
/// </summary>
|
||
private async Task MonitorButtonBoxConfigAsync(CancellationToken cancellationToken)
|
||
{
|
||
while (!cancellationToken.IsCancellationRequested)
|
||
{
|
||
try
|
||
{
|
||
// 读取配置文件
|
||
var configButtonBoxes = LoadButtonBoxConfig();
|
||
|
||
// 同步按钮盒列表
|
||
SyncButtonBoxes(configButtonBoxes);
|
||
|
||
// 等待10秒
|
||
await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// 正常取消,退出循环
|
||
break;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
// 记录错误,但继续运行
|
||
Diagnosis.Log($"按钮盒配置监控错误: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
// 发生错误时等待5秒后重试
|
||
try
|
||
{
|
||
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停止监控任务
|
||
/// </summary>
|
||
[MethodMember(Name = "停止进程")]
|
||
[I18N.DocumentTranslation(Name = "Stop Mission", locale = "en")]
|
||
public void Stop()
|
||
{
|
||
StopInternalAsync().GetAwaiter().GetResult();
|
||
status.status = "/";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 取消并释放当前的取消令牌源
|
||
/// </summary>
|
||
private async Task StopInternalAsync()
|
||
{
|
||
var cts = Interlocked.Exchange(ref _cancellationTokenSource, null);
|
||
var configTask = Interlocked.Exchange(ref _configTask, null);
|
||
var stateTask = Interlocked.Exchange(ref _stateTask, null);
|
||
|
||
if (cts == null && configTask == null && stateTask == null)
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
cts?.Cancel();
|
||
}
|
||
catch (ObjectDisposedException)
|
||
{
|
||
// 已释放,忽略
|
||
}
|
||
|
||
var runningTasks = new[] { configTask, stateTask }
|
||
.Where(t => t != null)
|
||
.ToArray();
|
||
|
||
if (runningTasks.Length > 0)
|
||
{
|
||
var aggregateTask = Task.WhenAll(runningTasks);
|
||
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(5));
|
||
var completedTask = await Task.WhenAny(aggregateTask, timeoutTask).ConfigureAwait(false);
|
||
|
||
if (completedTask == timeoutTask)
|
||
{
|
||
Diagnosis.Log("停止按钮监控任务超时", "ButtonMission", true);
|
||
}
|
||
else
|
||
{
|
||
try
|
||
{
|
||
await aggregateTask.ConfigureAwait(false);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"停止按钮监控任务时发生异常: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
}
|
||
}
|
||
|
||
cts?.Dispose();
|
||
|
||
DisconnectAllButtonBoxes();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 断开所有按钮盒连接
|
||
/// </summary>
|
||
private void DisconnectAllButtonBoxes()
|
||
{
|
||
List<BasicButtonBox> snapshot;
|
||
lock (_syncLock)
|
||
{
|
||
snapshot = _buttonBoxes.ToList();
|
||
}
|
||
|
||
foreach (var box in snapshot)
|
||
{
|
||
try
|
||
{
|
||
box.Disconnect();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"停止按钮盒失败: Index={box.Index}, Error={ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 监控按钮状态,用于触发按钮动作
|
||
/// </summary>
|
||
private async Task MonitorButtonStatesAsync(CancellationToken cancellationToken)
|
||
{
|
||
while (!cancellationToken.IsCancellationRequested)
|
||
{
|
||
try
|
||
{
|
||
List<(BasicButtonBox Box, ButtonModel Config)> snapshot;
|
||
lock (_syncLock)
|
||
{
|
||
snapshot = _buttonBoxes
|
||
.SelectMany(box => box.ButtonConfigs.Values.Select(cfg => (Box: box, Config: cfg)))
|
||
.ToList();
|
||
}
|
||
|
||
foreach (var (box, config) in snapshot)
|
||
{
|
||
if (box == null || config == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(config.TriggerMission) ||
|
||
string.IsNullOrWhiteSpace(config.TriggerMethod))
|
||
{
|
||
continue;
|
||
}
|
||
var desiredState = ButtonState.Pressed;
|
||
if (!string.IsNullOrWhiteSpace(config.TriggerState) &&
|
||
Enum.TryParse(config.TriggerState, out ButtonState parsedState))
|
||
{
|
||
desiredState = parsedState;
|
||
}
|
||
|
||
var currentState = box.GetButtonState(config.Index);
|
||
bool isActive = currentState == desiredState&&box.IsOnline;
|
||
|
||
int delay = config.TriggerDelay;
|
||
if (delay <= 0)
|
||
{
|
||
delay = 1;
|
||
}
|
||
|
||
int uniqueId = unchecked((box.Index << 16) ^ config.Index);
|
||
|
||
LadderLogic.TriggerOnce(isActive, delay*1000, () =>
|
||
{
|
||
ExecuteButtonAction(config, box);
|
||
}, uniqueId);
|
||
}
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
break;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"按钮状态监控错误: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
|
||
try
|
||
{
|
||
await Task.Delay(TimeSpan.FromMilliseconds(500), cancellationToken);
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载按钮盒配置文件
|
||
/// </summary>
|
||
private List<ButtonBoxModel> LoadButtonBoxConfig()
|
||
{
|
||
try
|
||
{
|
||
if (File.Exists(_dataFilePath))
|
||
{
|
||
var jsonContent = File.ReadAllText(_dataFilePath, Encoding.UTF8);
|
||
if (!string.IsNullOrWhiteSpace(jsonContent))
|
||
{
|
||
var buttonBoxes = jsonContent.JsonTo<List<ButtonBoxModel>>();
|
||
return buttonBoxes ?? new List<ButtonBoxModel>();
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"加载按钮盒配置文件失败: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
|
||
return new List<ButtonBoxModel>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 同步按钮盒列表,根据配置文件进行增删改
|
||
/// </summary>
|
||
private void SyncButtonBoxes(List<ButtonBoxModel> configButtonBoxes)
|
||
{
|
||
var boxesToAdd = new List<ButtonBoxModel>();
|
||
|
||
lock (_syncLock)
|
||
{
|
||
// 创建配置中的按钮盒索引字典,用于快速查找
|
||
var configDict = configButtonBoxes.ToDictionary(b => b.Index);
|
||
|
||
// 创建当前按钮盒索引字典
|
||
var currentDict = _buttonBoxes.ToDictionary(b => b.Index);
|
||
|
||
// 1. 删除:在配置中不存在的按钮盒
|
||
var toRemove = _buttonBoxes.Where(b => !configDict.ContainsKey(b.Index)).ToList();
|
||
foreach (var buttonBox in toRemove)
|
||
{
|
||
try
|
||
{
|
||
// 断开连接
|
||
buttonBox.Disconnect();
|
||
_buttonBoxes.Remove(buttonBox);
|
||
Diagnosis.Post($"删除按钮盒: Index={buttonBox.Index}, IP={buttonBox.Ip}", "ButtonMission", true);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"删除按钮盒失败: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
}
|
||
|
||
// 2. 添加和修改:遍历配置中的按钮盒
|
||
foreach (var configBox in configButtonBoxes)
|
||
{
|
||
if (currentDict.TryGetValue(configBox.Index, out var existingBox))
|
||
{
|
||
// 修改:检查是否需要更新
|
||
if (ShouldUpdateButtonBox(existingBox, configBox))
|
||
{
|
||
try
|
||
{
|
||
UpdateButtonBox(existingBox, configBox);
|
||
Diagnosis.Post($"更新按钮盒: Index={configBox.Index}, IP={configBox.Ip}, Type={configBox.Type}", "ButtonMission", true);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"更新按钮盒失败: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
boxesToAdd.Add(configBox);
|
||
}
|
||
}
|
||
}
|
||
|
||
foreach (var configBox in boxesToAdd)
|
||
{
|
||
try
|
||
{
|
||
var newBox = CreateButtonBoxInstance(configBox);
|
||
if (newBox != null)
|
||
{
|
||
lock (_syncLock)
|
||
{
|
||
_buttonBoxes.Add(newBox);
|
||
}
|
||
Diagnosis.Post($"添加按钮盒: Index={configBox.Index}, IP={configBox.Ip}, Type={configBox.Type}", "ButtonMission", true);
|
||
}
|
||
else
|
||
{
|
||
Diagnosis.Log($"无法创建按钮盒实例: Index={configBox.Index}, Type={configBox.Type}", "ButtonMission", true);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"添加按钮盒失败: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断是否需要更新按钮盒
|
||
/// </summary>
|
||
private bool ShouldUpdateButtonBox(BasicButtonBox existingBox, ButtonBoxModel configBox)
|
||
{
|
||
// 检查基本属性是否变更
|
||
if (existingBox.Ip != configBox.Ip
|
||
|| existingBox.Port != configBox.Port
|
||
|| existingBox.GetType().Name != configBox.Type)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
// 检查按钮信息是否变更
|
||
return HasButtonConfigsChanged(existingBox, configBox);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查按钮配置信息是否变更
|
||
/// </summary>
|
||
private bool HasButtonConfigsChanged(BasicButtonBox existingBox, ButtonBoxModel configBox)
|
||
{
|
||
var configButtons = configBox.Buttons ?? new List<ButtonModel>();
|
||
var configDict = configButtons.ToDictionary(b => b.Index);
|
||
var existingDict = existingBox.ButtonConfigs;
|
||
|
||
// 检查按钮数量是否变化
|
||
if (existingDict.Count != configDict.Count)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
// 检查每个按钮的配置是否变化
|
||
foreach (var configButton in configButtons)
|
||
{
|
||
if (!existingDict.TryGetValue(configButton.Index, out var existingButton))
|
||
{
|
||
// 新增了按钮
|
||
return true;
|
||
}
|
||
|
||
// 检查按钮配置是否变化
|
||
if (existingButton.TriggerMission != configButton.TriggerMission
|
||
|| existingButton.TriggerMethod != configButton.TriggerMethod
|
||
|| existingButton.TriggerMethodParams != configButton.TriggerMethodParams
|
||
|| existingButton.TriggerState != configButton.TriggerState
|
||
|| existingButton.TriggerDelay != configButton.TriggerDelay)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
// 检查是否有按钮被删除
|
||
foreach (var existingKey in existingDict.Keys)
|
||
{
|
||
if (!configDict.ContainsKey(existingKey))
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新按钮盒属性
|
||
/// </summary>
|
||
private void UpdateButtonBox(BasicButtonBox buttonBox, ButtonBoxModel configBox)
|
||
{
|
||
// 如果类型改变,需要重新创建实例
|
||
if (buttonBox.GetType().Name != configBox.Type)
|
||
{
|
||
// 断开旧连接
|
||
buttonBox.Disconnect();
|
||
|
||
// 从列表中移除
|
||
_buttonBoxes.Remove(buttonBox);
|
||
|
||
// 创建新实例
|
||
var newBox = CreateButtonBoxInstance(configBox);
|
||
if (newBox != null)
|
||
{
|
||
_buttonBoxes.Add(newBox);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 只更新属性
|
||
bool needReconnect = buttonBox.Ip != configBox.Ip || buttonBox.Port != configBox.Port;
|
||
buttonBox.Ip = configBox.Ip;
|
||
buttonBox.Port = configBox.Port;
|
||
|
||
// 更新按钮配置信息
|
||
buttonBox.UpdateButtonConfigs(configBox.Buttons);
|
||
|
||
// 初始化按钮状态(基于配置中的按钮索引)
|
||
var buttonIndices = configBox.Buttons?.Select(b => b.Index).ToList() ?? new List<int>();
|
||
buttonBox.InitializeButtons(buttonIndices);
|
||
|
||
// 如果IP或端口改变,需要重新连接
|
||
if (needReconnect)
|
||
{
|
||
buttonBox.Disconnect();
|
||
buttonBox.Connect();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过类型字符串创建按钮盒实例
|
||
/// </summary>
|
||
private BasicButtonBox CreateButtonBoxInstance(ButtonBoxModel configBox)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(configBox.Type))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
// 获取当前命名空间下所有继承自BasicButtonBox的类
|
||
// 跨程序集发现:按钮盒具体类型可能位于卫星插件 dll(StandardScene.Devices.ButtonBox),
|
||
// 用内核同款全域类型发现替代仅扫当前程序集的 GetExecutingAssembly。
|
||
var buttonBoxType = SimpleLite.Utils.UiTypeDiscovery.AllTypes()
|
||
.FirstOrDefault(t => t.IsClass
|
||
&& !t.IsAbstract
|
||
&& t.Namespace == typeof(BasicButtonBox).Namespace
|
||
&& t.IsSubclassOf(typeof(BasicButtonBox))
|
||
&& t.Name == configBox.Type);
|
||
|
||
if (buttonBoxType == null)
|
||
{
|
||
Diagnosis.Log($"未找到按钮盒类型: {configBox.Type}", "ButtonMission", true);
|
||
return null;
|
||
}
|
||
|
||
// 使用反射创建实例
|
||
var instance = (BasicButtonBox)Activator.CreateInstance(buttonBoxType);
|
||
|
||
// 设置属性
|
||
instance.Index = configBox.Index;
|
||
instance.Ip = configBox.Ip;
|
||
instance.Port = configBox.Port;
|
||
|
||
// 初始化按钮配置信息
|
||
instance.InitializeButtonConfigs(configBox.Buttons);
|
||
|
||
// 初始化按钮状态(基于配置中的按钮索引)
|
||
var buttonIndices = configBox.Buttons?.Select(b => b.Index).ToList() ?? new List<int>();
|
||
instance.InitializeButtons(buttonIndices);
|
||
|
||
// 自动连接
|
||
instance.Connect();
|
||
|
||
return instance;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"创建按钮盒实例失败: Type={configBox.Type}, Error={ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取当前所有按钮盒实例(只读)
|
||
/// </summary>
|
||
public IReadOnlyList<BasicButtonBox> GetButtonBoxes()
|
||
{
|
||
lock (_syncLock)
|
||
{
|
||
return _buttonBoxes.ToList().AsReadOnly();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 执行按钮动作(在独立线程中异步执行,避免阻塞按钮监控循环)
|
||
/// </summary>
|
||
private void ExecuteButtonAction(ButtonModel buttonConfig, BasicButtonBox buttonBox)
|
||
{
|
||
|
||
|
||
Task.Run(() => ExecuteButtonActionInternal(buttonConfig, buttonBox));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 实际执行业务方法的内部逻辑,包含成功/失败反馈。
|
||
/// </summary>
|
||
private void ExecuteButtonActionInternal(ButtonModel buttonConfig, BasicButtonBox buttonBox)
|
||
{
|
||
var success = false;
|
||
try
|
||
{
|
||
// 按钮动作执行后清零对应按钮寄存器(具体盒型按需重写,默认空实现)
|
||
buttonBox.ClearButtonRegister(buttonConfig.Index);
|
||
|
||
if (string.IsNullOrWhiteSpace(buttonConfig.TriggerMission) ||
|
||
string.IsNullOrWhiteSpace(buttonConfig.TriggerMethod))
|
||
{
|
||
// 配置不完整,直接反馈失败
|
||
Diagnosis.Log("按钮配置缺少 TriggerMission 或 TriggerMethod,无法执行动作", "ButtonMission", true);
|
||
return;
|
||
}
|
||
|
||
var mission = SimpleProject.proj?.Missions?
|
||
.FirstOrDefault(m => m.GetType().Name == buttonConfig.TriggerMission || m.name == buttonConfig.TriggerMission);
|
||
|
||
if (mission == null)
|
||
{
|
||
Diagnosis.Log($"未找到触发任务: {buttonConfig.TriggerMission}", "ButtonMission", true);
|
||
return;
|
||
}
|
||
|
||
var method = mission.GetType().GetMethod(buttonConfig.TriggerMethod,
|
||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
|
||
|
||
if (method == null)
|
||
{
|
||
Diagnosis.Log($"任务 {buttonConfig.TriggerMission} 中未找到方法 {buttonConfig.TriggerMethod}", "ButtonMission", true);
|
||
return;
|
||
}
|
||
|
||
var parameters = ParseMethodParameters(buttonConfig.TriggerMethodParams, method);
|
||
|
||
if (method.IsStatic)
|
||
{
|
||
var result = method.Invoke(null, parameters);
|
||
success = HandleMethodResult(result);
|
||
}
|
||
else
|
||
{
|
||
var result = method.Invoke(mission, parameters);
|
||
success = HandleMethodResult(result);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"执行按钮动作失败: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
}
|
||
finally
|
||
{
|
||
// 业务方法执行完成后,回调按钮盒进行反馈(如灯光、蜂鸣等)
|
||
try
|
||
{
|
||
buttonBox.OnActionExecuted(buttonConfig, success);
|
||
}
|
||
catch (Exception feedbackEx)
|
||
{
|
||
Diagnosis.Log($"按钮盒执行反馈失败: {ExceptionFormatter.FormatEx(feedbackEx)}", "ButtonMission", true);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理反射调用结果:支持 Task/Task<bool> 等异步返回类型。
|
||
/// 返回 true 表示执行成功。
|
||
/// </summary>
|
||
private bool HandleMethodResult(object result)
|
||
{
|
||
try
|
||
{
|
||
switch (result)
|
||
{
|
||
case null:
|
||
return true;
|
||
case Task<bool> tb:
|
||
return tb.GetAwaiter().GetResult();
|
||
case Task t:
|
||
t.GetAwaiter().GetResult();
|
||
return true;
|
||
case bool b:
|
||
return b;
|
||
default:
|
||
return true;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"按钮动作方法异步执行失败: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 解析方法参数
|
||
/// </summary>
|
||
private object[] ParseMethodParameters(string paramsStr, MethodInfo methodInfo)
|
||
{
|
||
var paramInfos = methodInfo.GetParameters();
|
||
|
||
if (paramInfos.Length == 0)
|
||
{
|
||
return Array.Empty<object>();
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(paramsStr))
|
||
{
|
||
return paramInfos.Select(p => p.HasDefaultValue ? p.DefaultValue : GetDefaultValue(p.ParameterType)).ToArray();
|
||
}
|
||
|
||
try
|
||
{
|
||
var paramStrings = paramsStr.Split(',');
|
||
var parameters = new List<object>();
|
||
|
||
for (int i = 0; i < paramInfos.Length; i++)
|
||
{
|
||
var paramInfo = paramInfos[i];
|
||
var paramType = paramInfo.ParameterType;
|
||
|
||
if (i < paramStrings.Length)
|
||
{
|
||
var trimmed = paramStrings[i].Trim();
|
||
parameters.Add(ConvertParameter(trimmed, paramType));
|
||
}
|
||
else
|
||
{
|
||
parameters.Add(paramInfo.HasDefaultValue ? paramInfo.DefaultValue : GetDefaultValue(paramType));
|
||
}
|
||
}
|
||
|
||
return parameters.ToArray();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Diagnosis.Log($"解析按钮参数失败: {ExceptionFormatter.FormatEx(ex)}", "ButtonMission", true);
|
||
return paramInfos.Select(p => p.HasDefaultValue ? p.DefaultValue : GetDefaultValue(p.ParameterType)).ToArray();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 转换参数
|
||
/// </summary>
|
||
private object ConvertParameter(string value, Type targetType)
|
||
{
|
||
if (targetType == typeof(string))
|
||
{
|
||
return value;
|
||
}
|
||
if (targetType == typeof(int) || targetType == typeof(int?))
|
||
{
|
||
return int.TryParse(value, out int result) ? result : (targetType == typeof(int?) ? (int?)null : 0);
|
||
}
|
||
if (targetType == typeof(double) || targetType == typeof(double?))
|
||
{
|
||
return double.TryParse(value, out double result) ? result : (targetType == typeof(double?) ? (double?)null : 0d);
|
||
}
|
||
if (targetType == typeof(float) || targetType == typeof(float?))
|
||
{
|
||
return float.TryParse(value, out float result) ? result : (targetType == typeof(float?) ? (float?)null : 0f);
|
||
}
|
||
if (targetType == typeof(bool) || targetType == typeof(bool?))
|
||
{
|
||
return bool.TryParse(value, out bool result) ? result : (targetType == typeof(bool?) ? (bool?)null : false);
|
||
}
|
||
if (targetType.IsEnum)
|
||
{
|
||
try
|
||
{
|
||
return Enum.Parse(targetType, value, true);
|
||
}
|
||
catch
|
||
{
|
||
return Enum.GetValues(targetType).GetValue(0);
|
||
}
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取类型默认值
|
||
/// </summary>
|
||
private object GetDefaultValue(Type type)
|
||
{
|
||
if (type.IsValueType)
|
||
{
|
||
return Activator.CreateInstance(type);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 打开按钮盒管理界面
|
||
/// </summary>
|
||
[MethodMember(Name = "打开管理界面")]
|
||
[I18N.DocumentTranslation(Name = "Open Manager", locale = "en")]
|
||
public static void OpenViewer()
|
||
{
|
||
try
|
||
{
|
||
var manager = ButtonBoxManager.Instance;
|
||
|
||
// 确保窗体没有被销毁
|
||
if (manager.IsDisposed)
|
||
{
|
||
// 如果窗体被销毁,单例会自动重新创建
|
||
manager = ButtonBoxManager.Instance;
|
||
}
|
||
|
||
if (manager.Visible)
|
||
{
|
||
// 如果界面已经可见,将其激活并置于最前
|
||
if (manager.WindowState == FormWindowState.Minimized)
|
||
{
|
||
manager.WindowState = FormWindowState.Normal;
|
||
}
|
||
manager.Activate();
|
||
manager.BringToFront();
|
||
}
|
||
else
|
||
{
|
||
// 如果界面不可见,显示它
|
||
manager.Show();
|
||
manager.Activate();
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"打开按钮盒管理界面失败: {ex.Message}", "错误",
|
||
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||
}
|
||
}
|
||
}
|
||
}
|