| | |
| | | using LB_VisionProcesses; |
| | | using System; |
| | | using System.Diagnostics; |
| | | using System.Linq; |
| | | using System.Reflection; |
| | | using System.Reflection.Emit; |
| | | using System.Text.Json.Nodes; |
| | |
| | | public string Group { get; set; } |
| | | public string Description { get; set; } |
| | | } |
| | | public abstract class IFlowContext |
| | | public class IFlowContext |
| | | { |
| | | public readonly Dictionary<string, MethodInfo> _nodeMethods |
| | | = new Dictionary<string, MethodInfo>(); |
| | |
| | | public readonly Dictionary<string, Func<FlowNode, bool>> _nodeDelegates |
| | | = new Dictionary<string, Func<FlowNode, bool>>(); |
| | | |
| | | // 自动生成的插件节点方法信息 |
| | | public readonly Dictionary<string, PluginNodeMethodInfo> _pluginNodeMethods |
| | | = new Dictionary<string, PluginNodeMethodInfo>(); |
| | | |
| | | // 动态方法的包装(用于模拟MethodInfo) |
| | | private readonly Dictionary<string, DynamicMethodWrapper> _dynamicMethodWrappers |
| | | = new Dictionary<string, DynamicMethodWrapper>(); |
| | | |
| | | // 是否已自动生成插件节点 |
| | | private bool _pluginNodesGenerated = false; |
| | | |
| | | // 动态方法包装类 |
| | | public class DynamicMethodWrapper |
| | | { |
| | | public string DisplayName { get; set; } |
| | | public string Category { get; set; } |
| | | public string Group { get; set; } |
| | | public string Description { get; set; } |
| | | public Func<FlowNode, bool> Execute { get; set; } |
| | | // 模拟MethodInfo的必要属性 |
| | | public string Name => DisplayName; |
| | | } |
| | | |
| | | public void InitializeMethods() |
| | | { |
| | | // 1. 先处理自身的Node特性方法 |
| | | var methods = GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance); |
| | | |
| | | foreach (var method in methods) |
| | | { |
| | | var nodeAttr = method.GetCustomAttribute<NodeAttribute>(); |
| | |
| | | _groupedMethods[nodeAttr.Group].Add(method); |
| | | } |
| | | } |
| | | |
| | | // 2. 自动为IProcess工具生成动态节点方法 |
| | | GeneratePluginNodeMethods(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 自动为IProcess工具生成节点方法(核心方法) |
| | | /// </summary> |
| | | private void GeneratePluginNodeMethods() |
| | | { |
| | | if (_pluginNodesGenerated) |
| | | return; |
| | | try |
| | | { |
| | | // 确保IProcess的插件管理器已初始化 |
| | | if (IProcess.dicProcesses == null || IProcess.dicProcesses.Count == 0) |
| | | { |
| | | var _ = IProcess.dicProcesses; // 触发初始化 |
| | | } |
| | | // 清空现有的插件节点方法 |
| | | _pluginNodeMethods.Clear(); |
| | | _dynamicMethodWrappers.Clear(); |
| | | // 遍历所有IProcess工具 |
| | | foreach (var processKvp in IProcess.dicProcesses) |
| | | { |
| | | string toolName = processKvp.Key; |
| | | string className = processKvp.Value; |
| | | // 获取工具的分类 |
| | | string category = GetCategoryForTool(toolName); |
| | | string group = GetGroupForCategory(category); // 根据分类确定组 |
| | | string description = $"{toolName}"; |
| | | |
| | | // 创建插件节点方法信息 |
| | | var pluginNode = new PluginNodeMethodInfo |
| | | { |
| | | DisplayName = toolName, |
| | | FullTypeName = className, |
| | | Category = category, |
| | | Group = group, |
| | | Description = description |
| | | }; |
| | | _pluginNodeMethods[toolName] = pluginNode; |
| | | |
| | | // 创建动态执行委托 |
| | | Func<FlowNode, bool> executeDelegate = (node) => |
| | | { |
| | | try |
| | | { |
| | | // 创建IProcess实例 |
| | | IProcess process = IProcess.CreateProcess(toolName); |
| | | if (process == null) |
| | | { |
| | | Debug.WriteLine($"无法创建工具实例: {toolName}"); |
| | | node.Result = false; |
| | | return false; |
| | | } |
| | | |
| | | // 初始化运行参数 |
| | | process.InitRunParams(); |
| | | |
| | | // 执行工具的Run方法 |
| | | bool runResult = process.Run(); |
| | | |
| | | // 设置节点结果 |
| | | node.Result = runResult; |
| | | node.BranchIndex = "0"; // 默认分支 |
| | | |
| | | // 释放资源 |
| | | process.Dispose(); |
| | | |
| | | Debug.WriteLine($"插件工具 {toolName} 执行完成,结果: {runResult}"); |
| | | return runResult; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.WriteLine($"插件工具 {toolName} 执行失败: {ex.Message}"); |
| | | node.Result = false; |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | // 创建动态方法包装 |
| | | var dynamicMethod = new DynamicMethodWrapper |
| | | { |
| | | DisplayName = toolName, |
| | | Category = category, |
| | | Group = group, |
| | | Description = description, |
| | | Execute = executeDelegate |
| | | }; |
| | | _dynamicMethodWrappers[description] = dynamicMethod; |
| | | |
| | | // ********** 关键:将动态方法添加到_nodeMethods和_groupedMethods ********** |
| | | // 方式:生成动态MethodInfo(使用Emit),或者模拟(这里用Emit生成真实的MethodInfo) |
| | | MethodInfo dynamicMethodInfo = CreateDynamicMethod(toolName, group, description); |
| | | |
| | | // 添加到_nodeMethods(键是description) |
| | | _nodeMethods[description] = dynamicMethodInfo; |
| | | |
| | | // 添加到_groupedMethods |
| | | if (!_groupedMethods.ContainsKey(group)) |
| | | { |
| | | _groupedMethods[group] = new List<MethodInfo>(); |
| | | } |
| | | _groupedMethods[group].Add(dynamicMethodInfo); |
| | | |
| | | // 添加到_nodeDelegates |
| | | _nodeDelegates[description] = executeDelegate; |
| | | |
| | | Debug.WriteLine($"自动生成插件节点: {toolName} (分类: {category}, 组: {group})"); |
| | | } |
| | | |
| | | _pluginNodesGenerated = true; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Debug.WriteLine($"自动生成插件节点方法失败: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 使用Reflection.Emit生成动态MethodInfo,模拟Node特性方法 |
| | | /// </summary> |
| | | /// <param name="toolName">工具名称</param> |
| | | /// <param name="group">组名</param> |
| | | /// <param name="description">描述</param> |
| | | /// <returns>动态生成的MethodInfo</returns> |
| | | private MethodInfo CreateDynamicMethod(string toolName, string group, string description) |
| | | { |
| | | // 1. 定义动态方法的参数和返回类型 |
| | | Type flowNodeType = typeof(FlowNode); |
| | | DynamicMethod dynamicMethod = new DynamicMethod( |
| | | toolName, // 方法名 |
| | | typeof(void), // 返回类型(和原有Node方法一致) |
| | | new[] { typeof(FlowNode) }, // 参数类型 |
| | | GetType(), // 所属类型 |
| | | true); // 跳过JIT可见性检查 |
| | | |
| | | // 2. 生成IL代码,调用动态委托 |
| | | ILGenerator il = dynamicMethod.GetILGenerator(); |
| | | // 加载参数(FlowNode) |
| | | il.Emit(OpCodes.Ldarg_1); // 注意:实例方法的第一个参数是this(Ldarg_0),这里动态方法是静态的,所以Ldarg_0是FlowNode |
| | | // 调用委托(这里简化,直接设置Result为true) |
| | | il.Emit(OpCodes.Ldflda, flowNodeType.GetProperty("Result").GetSetMethod()); |
| | | il.Emit(OpCodes.Ldc_I4_1); |
| | | il.Emit(OpCodes.Callvirt, flowNodeType.GetProperty("Result").GetSetMethod()); |
| | | // 设置BranchIndex |
| | | il.Emit(OpCodes.Ldarg_1); |
| | | il.Emit(OpCodes.Ldflda, flowNodeType.GetProperty("BranchIndex").GetSetMethod()); |
| | | il.Emit(OpCodes.Ldstr, "0"); |
| | | il.Emit(OpCodes.Callvirt, flowNodeType.GetProperty("BranchIndex").GetSetMethod()); |
| | | // 返回 |
| | | il.Emit(OpCodes.Ret); |
| | | |
| | | // 3. 将DynamicMethod包装为MethodInfo(DynamicMethod继承自MethodInfo) |
| | | return dynamicMethod; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据工具名称推断分类(完善逻辑) |
| | | /// </summary> |
| | | private string GetCategoryForTool(string toolName) |
| | | { |
| | | if (string.IsNullOrWhiteSpace(toolName)) |
| | | return "未分类"; |
| | | |
| | | toolName = toolName.ToLower(); |
| | | |
| | | if (toolName.Contains("相机") || toolName.Contains("取图")) |
| | | return "相机工具"; |
| | | else if (toolName.Contains("通讯") || toolName.Contains("command")) |
| | | return "通讯工具"; |
| | | else if (toolName.Contains("opencvsharp")) |
| | | return "OpencvSharp算法"; |
| | | else if (toolName.Contains("halcon")) |
| | | return "Halcon算法"; |
| | | else if (toolName.Contains("yolo") || toolName.Contains("tensorrt") || |
| | | toolName.Contains("ocr") || toolName.Contains("deeplearning") || toolName.Contains("大模型")) |
| | | return "深度学习"; |
| | | else if (toolName.Contains("图像处理") || toolName.Contains("点云") || |
| | | toolName.Contains("线线交点")) |
| | | return "图像处理工具"; |
| | | else if (toolName.Contains("测试") || toolName.Contains("检查") || |
| | | toolName.Contains("端口") || toolName.Contains("屏幕") || |
| | | toolName.Contains("工序") || toolName.Contains("转产")) |
| | | return "自定义工具"; |
| | | else if (toolName.Contains("脚本") || toolName.Contains("分支") || |
| | | toolName.Contains("延时") || toolName.Contains("绘制")) |
| | | return "工具"; |
| | | else if (toolName.Contains("固定跟随") || toolName.Contains("fixture")) |
| | | return "工具"; |
| | | else |
| | | return "插件工具"; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据分类确定组名 |
| | | /// </summary> |
| | | private string GetGroupForCategory(string category) |
| | | { |
| | | switch (category) |
| | | { |
| | | case "通讯工具": |
| | | return "Basic"; |
| | | case "算法": |
| | | return "Basic"; |
| | | case "深度学习": |
| | | return "Basic"; |
| | | case "图像处理工具": |
| | | return "Basic"; |
| | | case "自定义工具": |
| | | return "Basic"; |
| | | case "工具": |
| | | return "Basic"; |
| | | default: |
| | | return "Plugin"; |
| | | } |
| | | } |
| | | |
| | | public void InitializeDelegates() |
| | | { |
| | | // 1. 处理自身的Node方法 |
| | | foreach (var kvp in _nodeMethods) |
| | | { |
| | | var method = kvp.Value; |
| | | var parameters = method.GetParameters(); |
| | | |
| | | //如果是动态方法(DynamicMethod),跳过(已经在GeneratePluginNodeMethods中添加了委托) |
| | | if (method is DynamicMethod) |
| | | { |
| | | // 从动态方法包装中获取对应的委托 |
| | | if (_dynamicMethodWrappers.TryGetValue(kvp.Key, out var wrapper)) |
| | | { |
| | | // 直接使用包装中的Execute委托 |
| | | _nodeDelegates[kvp.Key] = wrapper.Execute; |
| | | } |
| | | else |
| | | { |
| | | // 如果没有找到包装,创建一个默认的执行委托 |
| | | _nodeDelegates[kvp.Key] = (node) => |
| | | { |
| | | Debug.WriteLine($"执行动态方法: {kvp.Key}"); |
| | | node.Result = true; |
| | | node.BranchIndex = "0"; |
| | | return true; |
| | | }; |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | if (parameters.Length == 0) |
| | | { |
| | | // 无参数方法 |
| | | var action = (Action)Delegate.CreateDelegate(typeof(Action), this, method); |
| | | _nodeDelegates[kvp.Key] = (node) => { action(); return node.Result; }; |
| | | } |
| | | else if (parameters.Length == 1 && parameters[0].ParameterType == typeof(FlowNode)) |
| | | { |
| | | // 带FlowNode参数的方法 |
| | | var action = (Action<FlowNode>)Delegate.CreateDelegate(typeof(Action<FlowNode>), this, method); |
| | | _nodeDelegates[kvp.Key] = (node) => { action(node); return node.Result; }; |
| | | } |
| | | } |
| | | |
| | | // 2. 确保动态方法的委托已添加(GeneratePluginNodeMethods中已处理) |
| | | } |
| | | |
| | | public virtual bool ExecuteNode(FlowNode node) |
| | |
| | | if (string.IsNullOrEmpty(node.Description)) |
| | | return false; |
| | | |
| | | // 优先检查动态委托 |
| | | // 使用委托缓存,避免反射开销 |
| | | if (_nodeDelegates.TryGetValue(node.Description, out var nodeDelegate)) |
| | | { |
| | | try |
| | |
| | | } |
| | | } |
| | | |
| | | // 兼容原有逻辑 |
| | | return false; |
| | | } |
| | | |
| | |
| | | ); |
| | | } |
| | | |
| | | // 获取按组分组的可用节点(包含动态生成的插件节点) |
| | | // 获取按组分组的可用节点 |
| | | public Dictionary<string, List<ToolStripMenuItem>> GetGroupedMenuItems(EventHandler clickHandler) |
| | | { |
| | | var groupedMenuItems = new Dictionary<string, List<ToolStripMenuItem>>(); |
| | |
| | | |
| | | foreach (var method in group.Value) |
| | | { |
| | | string menuText; |
| | | string toolTip; |
| | | |
| | | // 判断是静态方法还是动态方法 |
| | | if (method is DynamicMethod dynamicMethod) |
| | | { |
| | | // 动态方法(插件工具) |
| | | var pluginNode = _pluginNodeMethods.Values.FirstOrDefault(p => p.DisplayName == dynamicMethod.Name); |
| | | menuText = pluginNode?.DisplayName ?? dynamicMethod.Name; |
| | | toolTip = pluginNode?.Description ?? $"动态工具: {dynamicMethod.Name}"; |
| | | } |
| | | else |
| | | { |
| | | // 静态方法(原有Node特性方法) |
| | | var nodeAttr = method.GetCustomAttribute<NodeAttribute>(); |
| | | menuText = nodeAttr?.Name ?? method.Name; |
| | | toolTip = nodeAttr?.Description ?? method.Name; |
| | | } |
| | | |
| | | var menuItem = new ToolStripMenuItem |
| | | { |
| | | Text = menuText, |
| | | Tag = menuText, // 存储描述作为标识 |
| | | ToolTipText = toolTip |
| | | Text = nodeAttr.Name, |
| | | Tag = nodeAttr.Description, // 存储描述作为标识 |
| | | ToolTipText = nodeAttr.Description |
| | | }; |
| | | |
| | | if (clickHandler != null) |
| | |
| | | return groupedMenuItems; |
| | | } |
| | | |
| | | // 获取按类别分组的菜单项(包含动态生成的插件节点) |
| | | |
| | | // 获取按类别分组的菜单项 |
| | | public Dictionary<string, List<ToolStripMenuItem>> GetCategorizedMenuItems(EventHandler clickHandler) |
| | | { |
| | | var categorizedMethods = new Dictionary<string, List<MethodInfo>>(); |
| | | |
| | | // 1. 处理原有Node方法 |
| | | foreach (var method in _nodeMethods.Values.Where(m => !(m is DynamicMethod))) |
| | | foreach (var method in _nodeMethods.Values) |
| | | { |
| | | var nodeAttr = method.GetCustomAttribute<NodeAttribute>(); |
| | | if (nodeAttr == null) continue; |
| | | |
| | | if (!categorizedMethods.ContainsKey(nodeAttr.Category)) |
| | | { |
| | | categorizedMethods[nodeAttr.Category] = new List<MethodInfo>(); |
| | |
| | | categorizedMethods[nodeAttr.Category].Add(method); |
| | | } |
| | | |
| | | // 2. 处理动态插件方法 |
| | | foreach (var pluginNode in _pluginNodeMethods.Values) |
| | | { |
| | | if (!categorizedMethods.ContainsKey(pluginNode.Category)) |
| | | { |
| | | categorizedMethods[pluginNode.Category] = new List<MethodInfo>(); |
| | | } |
| | | |
| | | // 找到对应的动态MethodInfo |
| | | var dynamicMethod = _nodeMethods.Values |
| | | .OfType<DynamicMethod>() |
| | | .FirstOrDefault(m => m.Name == pluginNode.DisplayName); |
| | | |
| | | if (dynamicMethod != null) |
| | | { |
| | | categorizedMethods[pluginNode.Category].Add(dynamicMethod); |
| | | } |
| | | } |
| | | |
| | | // 生成菜单项 |
| | | var categorizedMenuItems = new Dictionary<string, List<ToolStripMenuItem>>(); |
| | | |
| | | foreach (var category in categorizedMethods) |
| | | { |
| | | var menuItems = new List<ToolStripMenuItem>(); |
| | | |
| | | foreach (var method in category.Value) |
| | | { |
| | | string menuText; |
| | | string toolTip; |
| | | |
| | | if (method is DynamicMethod dynamicMethod) |
| | | { |
| | | var pluginNode = _pluginNodeMethods.Values.FirstOrDefault(p => p.DisplayName == dynamicMethod.Name); |
| | | menuText = pluginNode?.DisplayName ?? dynamicMethod.Name; |
| | | toolTip = pluginNode?.Description ?? $"动态工具: {dynamicMethod.Name}"; |
| | | } |
| | | else |
| | | { |
| | | var nodeAttr = method.GetCustomAttribute<NodeAttribute>(); |
| | | menuText = nodeAttr?.Name ?? method.Name; |
| | | toolTip = $"{nodeAttr?.Group} - {nodeAttr?.Description}"; |
| | | } |
| | | |
| | | var menuItem = new ToolStripMenuItem |
| | | { |
| | | Text = menuText, |
| | | Tag = menuText, |
| | | ToolTipText = toolTip |
| | | Text = nodeAttr.Name, |
| | | Tag = nodeAttr.Description, |
| | | ToolTipText = $"{nodeAttr.Group} - {nodeAttr.Description}" |
| | | }; |
| | | |
| | | if (clickHandler != null) |
| | |
| | | return categorizedMenuItems; |
| | | } |
| | | |
| | | // 原有Node方法 |
| | | [Node("开始", "控制", "Logic", "开始")] |
| | | public virtual void 开始(FlowNode node) { node.Result = true; } |
| | | |
| | |
| | | [Node("并行分支结束", "控制", "Logic", "并行分支结束")] |
| | | public virtual void 并行分支结束(FlowNode node) { node.Result = true; } |
| | | } |
| | | |
| | | public class FlowContext : IFlowContext |
| | | { |
| | | /// <summary> |
| | |
| | | |
| | | public FlowContext() |
| | | { |
| | | //GenerateFixedNodeMethods(); |
| | | InitializeMethods(); |
| | | InitializeDelegates(); |
| | | } |
| | | |
| | | |
| | | // 统一的动态节点执行辅助方法(可选) |
| | | private void RunNodeAsync(FlowNode node) |
| | |
| | | } |
| | | } |
| | | |
| | | // 保留原有测试方法(可选,也可以移除,由动态生成替代) |
| | | [Node("测试工具", "算法", "Basic", "测试工具")] |
| | | public void 测试工具(FlowNode node) { RunNodeAsync(node); } |
| | | } |
| | | |
| | | } |