using HalconDotNet;
using LB_SmartVision.Forms;
using LB_SmartVision.Forms.Pages;
using LB_SmartVision.Forms.Pages.CameraPage;
using LB_SmartVision.Forms.Pages.CommunicatorPage;
using LB_SmartVision.Forms.Pages.HistoricalData;
using LB_SmartVision.Forms.Pages.MESPage;
using LB_SmartVision.Forms.Pages.MotionControlPage;
using LB_SmartVision.Forms.Pages.ProcessPage;
using LB_SmartVision.Forms.Pages.SettingPage;
using LB_SmartVision.Forms.Pages.UserManagementPage;
using LB_SmartVision.ProcessRun;
using LB_SmartVision.Tool;
using LB_SmartVisionCommon;
using LB_SmartVisionLoginUI;
using LB_VisionProcesses;
using LB_VisionProcesses.Cameras;
using LB_VisionProcesses.Cameras.HRCameras;
using LB_VisionProcesses.Cameras.LBCameras;
using LB_VisionProcesses.Communicators;
using LB_VisionProcesses.Communicators.TCom;
using LB_VisionProcesses.Forms;
using log4net.Config;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Sunny.UI;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace LB_SmartVision
{
public partial class VisionForm : Form
{
AllProcessesPage AllProcessesPages = new AllProcessesPage();
CamerasEditPage CamerasEditPage = new CamerasEditPage();
HistoricalDataEditPage HistoricalDataEditPage = new HistoricalDataEditPage();
CommunicatorsEditPage CommunicatorsEditPage = new CommunicatorsEditPage();
SettingEditPage SettingEditPage = new SettingEditPage();
MESEditPage MESEditPage = new MESEditPage();
MotionControlEditPage MotionControlEditPage = new MotionControlEditPage();
UserManagementEditPage UserManagementEditPage = new UserManagementEditPage();
byte[] Assembly_LB_VisionProcessesBytes = File.ReadAllBytes("LB_VisionProcesses.dll");
///
/// 用于反序列化的程序集引用
///
Assembly Assembly_LB_VisionProcessesDll = null;
public VisionForm()
{
InitializeComponent();
HOperatorSet.SetWindowAttr("background_color", "gray");
Assembly_LB_VisionProcessesDll = Assembly.Load(Assembly_LB_VisionProcessesBytes);
GlobalVar.dicCommunicators.DictionaryChanged += CommunicatorsChanged;
GlobalVar.dicProcesses.DictionaryChanged += ProcessRunBllChanged;
//最开始就清空所有Tab页
materialTabControl.TabPages.Clear();
AllProcessesPages.controlsPanel.Dock = DockStyle.Fill;
materialTabControl.Controls.Add(AllProcessesPages);
HistoricalDataEditPage.LogInfo += LogInfo;
materialTabControl.Controls.Add(new MyPage(HistoricalDataEditPage));
CamerasEditPage.LogInfo += LogInfo;
materialTabControl.Controls.Add(new MyPage(CamerasEditPage));
CommunicatorsEditPage.LogInfo += LogInfo;
materialTabControl.Controls.Add(new MyPage(CommunicatorsEditPage));
SettingEditPage.LogInfo += LogInfo;
materialTabControl.Controls.Add(new MyPage(SettingEditPage));
MESEditPage.LogInfo += LogInfo;
materialTabControl.Controls.Add(new MyPage(MESEditPage));
MotionControlEditPage.LogInfo += LogInfo;
materialTabControl.Controls.Add(new MyPage(MotionControlEditPage));
UserManagementEditPage.LogInfo += LogInfo;
materialTabControl.Controls.Add(new MyPage(UserManagementEditPage));
for (int i = 0; i < materialTabControl.TabPages.Count; i++)
{
//materialTabControl.TabPages[i].Font= new Font("Microsoft YaHei UI", 18F, FontStyle.Regular, GraphicsUnit.Point, 0);
}
materialTabSelector.BaseTabControl = materialTabControl;
//materialTabSelector.Font = new Font("Microsoft YaHei UI", 18F, FontStyle.Regular, GraphicsUnit.Point, 0);
}
private void ProcessRunBllChanged(object? sender, DictionaryChangedEventArgs e)
{
try
{
string msg = string.Empty;
List removeMyPage = new List();
switch (e.ChangeType)
{
case DictionaryChangeType.Added:
string AddProcessName = e.NewKey;
GlobalVar.dicProcesses[AddProcessName].LogInfo += LogInfo;
if (GlobalVar.dicProcesses[AddProcessName].Load(out msg))
{
LogInfo($"流程[{AddProcessName}]加载成功", LogInfoType.PASS);
IProcess.dicGlobalVars.TryAdd($"{AddProcessName}.Result", false);
IProcess.dicGlobalVars.TryAdd($"{AddProcessName}.Msg", "");
ProcessRunBll processRunBll = GlobalVar.dicProcesses[AddProcessName];
ProcessPage ProcessPage = new ProcessPage(processRunBll.Name, processRunBll);
ProcessPage.LogInfo += LogInfo;
if (materialTabControl.InvokeRequired)
{
materialTabControl.Invoke(new Action(() =>
{
materialTabControl.Controls.Add(new MyPage(ProcessPage));
}));
}
else
materialTabControl.Controls.Add(new MyPage(ProcessPage));
}
else
LogInfo($"流程[{AddProcessName}]加载失败,原因是{msg}", LogInfoType.ERROR);
LogInfo($"添加流程[{AddProcessName}]", LogInfoType.INFO);
break;
case DictionaryChangeType.Removed:
string RemoveProcessName = e.OldKey;
foreach (var control in materialTabControl.Controls)
{
if (control != null && control is MyPage && ((MyPage)control).UserControl is ProcessPage processPage)
{
if (processPage.Text == RemoveProcessName)
{
IProcess.dicGlobalVars.TryRemove($"{RemoveProcessName}.Result", out _);
IProcess.dicGlobalVars.TryRemove($"{RemoveProcessName}.Msg", out _);
processPage.LogInfo -= LogInfo;
removeMyPage.Add((MyPage)control);
}
}
}
foreach (var myPage in removeMyPage)
{
if (materialTabControl.InvokeRequired)
{
materialTabControl.Invoke(new Action(() =>
{
materialTabControl.Controls.Remove(myPage);
}));
}
else
materialTabControl.Controls.Remove(myPage);
}
LogInfo($"移除流程[{RemoveProcessName}]", LogInfoType.INFO);
break;
case DictionaryChangeType.Renamed:
string OldProcessName = e.OldKey;
string NewProcessName = e.NewKey;
try
{
IProcess.dicGlobalVars.TryRemove($"{OldProcessName}.Result", out object obj1);
IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Result", obj1);
IProcess.dicGlobalVars.TryRemove($"{OldProcessName}.Msg", out object obj2);
IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Msg", obj2);
}
catch { }
LB_SmartVision.Tool.Tool.RenameDirectory(GlobalVar.allProcessPath + "\\" + OldProcessName
, GlobalVar.allProcessPath + "\\" + NewProcessName);
e.NewValue.Name = NewProcessName;
foreach (var control in materialTabControl.Controls)
{
if (control != null && control is MyPage && ((MyPage)control).UserControl is ProcessPage)
{
ProcessPage processPage = ((MyPage)control).UserControl as ProcessPage;
if (processPage.Text == OldProcessName)
{
if (materialTabControl.InvokeRequired)
{
materialTabControl.Invoke(new Action(() =>
{
materialTabControl.Controls.Remove((MyPage)control);
}));
}
else
materialTabControl.Controls.Remove((MyPage)control);
if (GlobalVar.dicProcesses[NewProcessName].Load(out msg))
{
LogInfo($"流程[{NewProcessName}]重命名后加载成功", LogInfoType.PASS);
IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Result", false);
IProcess.dicGlobalVars.TryAdd($"{NewProcessName}.Msg", "");
ProcessRunBll processRunBll = GlobalVar.dicProcesses[NewProcessName];
ProcessPage ProcessPage = new ProcessPage(processRunBll.Name, processRunBll);
ProcessPage.LogInfo += LogInfo;
if (materialTabControl.InvokeRequired)
{
materialTabControl.Invoke(new Action(() =>
{
materialTabControl.Controls.Add(new MyPage(ProcessPage));
}));
}
else
materialTabControl.Controls.Add(new MyPage(ProcessPage));
}
else
LogInfo($"流程[{NewProcessName}]重命名后加载失败,原因是{msg}", LogInfoType.ERROR);
}
}
}
LogInfo(string.Format("重命名流程名[{0}]修改为[{1}]", OldProcessName, NewProcessName), LogInfoType.INFO);
break;
}
}
catch { }
}
private void CommunicatorsChanged(object? sender, DictionaryChangedEventArgs e)
{
}
private void LogInfo(string strLog, LogInfoType infoType)
{
if (string.IsNullOrEmpty(strLog))
{
return;
}
string strInfo = DateTime.Now.ToString("[yyyy:MM:dd:HH:mm:ss:fff] ");
strInfo += strLog;
if (infoType != LogInfoType.NOSHOW)
{
// 如果当前不是 UI 线程,则通过 Invoke 将操作调度到 UI 线程
if (this.rich_Info.InvokeRequired)
{
this.rich_Info.BeginInvoke(new Action((msg) =>
{
if (this.rich_Info.Lines.Length > 1000)
{
this.rich_Info.Clear();
}
switch (infoType)
{
case LogInfoType.INFO:
{
this.rich_Info.SelectionColor = Color.Wheat;
AsyncLogHelper.Info(strLog);
break;
}
case LogInfoType.WARN:
{
this.rich_Info.SelectionColor = Color.Yellow;
AsyncLogHelper.Warn(strLog);
break;
}
case LogInfoType.PASS:
{
this.rich_Info.SelectionColor = Color.Green;
AsyncLogHelper.Info(strLog);
break;
}
case LogInfoType.ERROR:
{
this.rich_Info.SelectionColor = Color.Red;
AsyncLogHelper.Error(strLog);
break;
}
}
// 更新 UI 控件,比如显示接收到的消息
this.rich_Info.AppendText(strInfo);
this.rich_Info.AppendText("\r\n");
this.rich_Info.SelectionStart = this.rich_Info.Text.Length;
this.rich_Info.ScrollToCaret();
}), strInfo);
}
else
{
if (this.rich_Info.Lines.Length > 1000)
{
this.rich_Info.Clear();
}
// 如果已经在 UI 线程上,直接更新 UI
switch (infoType)
{
case LogInfoType.INFO:
{
this.rich_Info.SelectionColor = Color.Wheat;
AsyncLogHelper.Info(strLog);
break;
}
case LogInfoType.WARN:
{
this.rich_Info.SelectionColor = Color.Yellow;
AsyncLogHelper.Warn(strLog);
break;
}
case LogInfoType.PASS:
{
this.rich_Info.SelectionColor = Color.Green;
AsyncLogHelper.Info(strLog);
break;
}
case LogInfoType.ERROR:
{
this.rich_Info.SelectionColor = Color.Red;
AsyncLogHelper.Error(strLog);
break;
}
}
this.rich_Info.AppendText(strInfo);
this.rich_Info.AppendText("\r\n");
this.rich_Info.SelectionStart = this.rich_Info.Text.Length;
this.rich_Info.ScrollToCaret();
}
}
}
public static bool SaveAllLayout()
{
try
{
string strJson = string.Empty;
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
// 自定义缩进(4空格)
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
strJson = JsonConvert.SerializeObject(GlobalVar.dicLayout, settings);
//判断文件夹是否存在,防呆输入为文件名称
string directoryPath = Path.GetDirectoryName(GlobalVar.allLayoutPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch { }
}
File.WriteAllText(GlobalVar.allLayoutPath, strJson, Encoding.UTF8);
return true;
}
catch { return false; }
}
public static bool LoadAllCsv(string allCsvPath)
{
try
{
if (!File.Exists(allCsvPath))
{
Debug.WriteLine("文件不存在创建空文件");
// 获取不带文件名的目录路径
string directoryPath = Path.GetDirectoryName(allCsvPath);
SaveAllCsv();
return true;
}
string strJson = string.Empty;
using (StreamReader streamReader = new StreamReader(allCsvPath, Encoding.UTF8))
{
strJson = streamReader.ReadToEnd();
streamReader.Close();
}
GlobalVar.dicCsvSetting.Clear();
GlobalVar.dicCsvSetting = JsonConvert.DeserializeObject>(strJson);
if (GlobalVar.dicCsvSetting == null)
{
GlobalVar.dicCsvSetting = new ConcurrentDictionary();
return false;
}
return true;
}
catch { return false; }
}
public static bool SaveAllCsv()
{
try
{
string strJson = string.Empty;
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
// 自定义缩进(4空格)
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
strJson = JsonConvert.SerializeObject(GlobalVar.dicCsvSetting, settings);
//判断文件夹是否存在,防呆输入为文件名称
string directoryPath = Path.GetDirectoryName(GlobalVar.allCsvPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch { }
}
File.WriteAllText(GlobalVar.allCsvPath, strJson, Encoding.UTF8);
return true;
}
catch { return false; }
}
public bool LoadAllProcessSetting(string allProcessSettingStringPath)
{
try
{
if (!File.Exists(allProcessSettingStringPath))
{
Debug.WriteLine("文件不存在创建空文件");
// 获取不带文件名的目录路径
string directoryPath = Path.GetDirectoryName(allProcessSettingStringPath);
SaveAllProcessSetting();
return true;
}
string strJson = string.Empty;
using (StreamReader streamReader = new StreamReader(allProcessSettingStringPath, Encoding.UTF8))
{
strJson = streamReader.ReadToEnd();
streamReader.Close();
}
GlobalVar.dicProcessSetting = JsonConvert.DeserializeObject>>(strJson);
if (GlobalVar.dicProcessSetting == null)
GlobalVar.dicProcessSetting = new ConcurrentDictionary>();
try
{
string json = File.ReadAllText(GlobalVar.allRunSettingStringPath);
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto // 处理多态类型
};
GlobalVar.ControlStates = JsonConvert.DeserializeObject>(json, settings);
}
catch { }
return true;
}
catch { return false; }
}
public static bool SaveAllProcessSetting()
{
try
{
string strJson = string.Empty;
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
// 自定义缩进(4空格)
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
strJson = JsonConvert.SerializeObject(GlobalVar.dicProcessSetting, settings);
//判断文件夹是否存在,防呆输入为文件名称
string directoryPath = Path.GetDirectoryName(GlobalVar.allProcessSettingStringPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch { }
}
File.WriteAllText(GlobalVar.allProcessSettingStringPath, strJson, Encoding.UTF8);
//LogInfo($"流程设置保存成功", LogInfoType.INFO);
return true;
}
catch { return false; }
}
private void EnsureDirectory(string path)
{
// 如果是相对路径,转换为绝对路径
string fullPath = Path.IsPathRooted(path) ? path : Path.GetFullPath(path);
if (!Directory.Exists(fullPath))
{
Directory.CreateDirectory(fullPath);
LogInfo($"✅ 目录创建: {fullPath}", LogInfoType.INFO);
}
else
{
LogInfo($"ℹ️ 目录已存在: {fullPath}", LogInfoType.INFO);
}
}
private void VisionForm_Load(object sender, EventArgs e)
{
XmlConfigurator.Configure(new System.IO.FileInfo("log4net.config"));
string[] paths = {
@"生产日志\Run",
@"生产日志\Debug",
@"生产日志\Error",
@"生产日志\Fatal",
@"生产日志\Warn",
};
foreach (string path in paths)
{
EnsureDirectory(path);
}
if (!LB_SmartVision.Tool.Tool.ReadStringConfig("数据库名称", out string DateBaseName))
{
DateBaseName = "产品0";
LB_SmartVision.Tool.Tool.WriteConfig("数据库名称", DateBaseName);
LB_SmartVision.Tool.Tool.WriteConfig("产品列表", DateBaseName);
}
LB_SmartVision.Tool.Tool.ReadStringConfig("User ID", out string User_ID);
LB_SmartVision.Tool.Tool.ReadStringConfig("Password", out string Password);
GlobalVar.strProductName = DateBaseName;
//加载通讯
foreach (BaseCommunicator com in GlobalVar.dicCommunicators.Values)
{
com.Disconnect();
}
GlobalVar.dicCommunicators.Clear();
if (LoadAllCommunicators(GlobalVar.allCommunicatorsConnectionStringPath))
{
LogInfo("通讯加载成功", LogInfoType.PASS);
}
else
{
LogInfo("通讯加载失败", LogInfoType.ERROR);
}
//加载相机
foreach (BaseCamera camera in GlobalVar.dicCameras.Values)
{
camera.Dispose();
}
GlobalVar.dicCameras.Clear();
if (LoadAllCameras(GlobalVar.allCamerasConnectionStringPath))
{
LogInfo("相机加载成功", LogInfoType.PASS);
}
else
{
LogInfo("相机加载失败", LogInfoType.ERROR);
}
//加载全局变量
IProcess.dicGlobalVars.Clear();
if (LoadAllProcessVars(GlobalVar.allProcessVarsPath))
{
LogInfo("全局变量加载成功", LogInfoType.PASS);
}
else
{
LogInfo("全局变量加载失败", LogInfoType.ERROR);
}
//加载流程
GlobalVar.dicProcesses.Clear();
if (LoadAllProcess(GlobalVar.allProcessConnectionStringPath))
{
LogInfo("流程加载成功", LogInfoType.PASS);
}
else
{
LogInfo("流程加载失败", LogInfoType.ERROR);
}
//加载触发设置
if (LoadAllProcessSetting(GlobalVar.allProcessSettingStringPath))
{
LogInfo("流程设置加载成功", LogInfoType.PASS);
}
else
{
LogInfo("流程设置加载失败", LogInfoType.ERROR);
}
//加载流程布局
GlobalVar.dicLayout.Clear();
if (LoadAllLayout(GlobalVar.allLayoutPath))
{
LogInfo("流程布局加载成功", LogInfoType.PASS);
}
else
{
LogInfo("流程布局加载失败", LogInfoType.ERROR);
}
//加载流程表格
GlobalVar.dicCsvSetting.Clear();
if (LoadAllCsv(GlobalVar.allCsvPath))
{
LogInfo("流程表格加载成功", LogInfoType.PASS);
}
else
{
LogInfo("流程表格加载失败", LogInfoType.ERROR);
}
//显示所有产品
com_ProductName.Items.Clear();
LB_SmartVision.Tool.Tool.ReadStringConfig("产品列表", out string Products);
List lstProduct = (Products.Split(',')).ToList();
foreach (string DatabaseName in lstProduct)
{
com_ProductName.Items.Add(DatabaseName);
}
com_ProductName.Items.Add("新增");
com_ProductName.Text = GlobalVar.strProductName;
this.WindowState = FormWindowState.Maximized;
}
public void SaveAllSetting()
{
SaveAllProcess();
SaveAllProcessVars();
SaveAllCommunicators();
SaveAllCameras();
SaveAllProcessSetting();
SaveAllLayout();
SaveAllCsv();
}
public bool LoadAllCameras(string allCamerasConnectionStringPath)
{
if (!File.Exists(allCamerasConnectionStringPath))
{
Debug.WriteLine("文件不存在创建空文件");
// 获取不带文件名的目录路径
string directoryPath = Path.GetDirectoryName(allCamerasConnectionStringPath);
SaveAllCameras();
return true;
}
string strJson = string.Empty;
using (StreamReader streamReader = new StreamReader(allCamerasConnectionStringPath, Encoding.UTF8))
{
strJson = streamReader.ReadToEnd();
streamReader.Close();
}
GlobalVar.allCamerasConnectionString = JsonConvert.DeserializeObject>(strJson);
if (GlobalVar.allCamerasConnectionString == null)
{
MessageBox.Show("相机加载失败!", "异常");
return false;
}
BaseCamera camera = null;
foreach (var CameraConnectionString in GlobalVar.allCamerasConnectionString)
{
Enum.TryParse(CameraConnectionString.Value, out CameraBrand brand);
switch (brand)
{
case CameraBrand.HRCamera:
{
camera = new HRCamera();
break;
}
case CameraBrand.LBCamera:
{
//camera = new LBCamera();
break;
}
default:
{
MessageBox.Show($"[{CameraConnectionString.Key}]品牌不支持!", "异常");
continue;
}
}
camera.SN = CameraConnectionString.Key;
if (!camera.InitDevice(CameraConnectionString.Key, this.Handle))
{
LogInfo($"初始化相机[{CameraConnectionString.Key}]失败", LogInfoType.ERROR);
if (camera != null)
camera.isGrabbing = false;
}
GlobalVar.dicCameras.TryAdd(CameraConnectionString.Key, camera);
}
return true;
}
public bool SaveAllCameras()
{
try
{
string strJson = string.Empty;
GlobalVar.allCamerasConnectionString = new ConcurrentDictionary();
foreach (var item in GlobalVar.dicCameras)
{
string CameraSN = item.Value.SN;// "TCP"
string CameraBrand = item.Value.Brand.ToString();//"1111"
if (string.IsNullOrEmpty(CameraSN) || string.IsNullOrEmpty(CameraBrand))
{
break;
}
GlobalVar.allCamerasConnectionString.TryAdd(CameraSN, CameraBrand);
}
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
// 自定义缩进(4空格)
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
strJson = JsonConvert.SerializeObject(GlobalVar.allCamerasConnectionString, settings);
//判断文件夹是否存在,防呆输入为文件名称
string directoryPath = Path.GetDirectoryName(GlobalVar.allCamerasConnectionStringPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch (Exception)
{ }
}
File.WriteAllText(GlobalVar.allCamerasConnectionStringPath, strJson, Encoding.UTF8);
return true;
}
catch { return false; }
}
public bool LoadAllCommunicators(string allCommunicatorsConnectionStringPath)
{
try
{
if (!File.Exists(allCommunicatorsConnectionStringPath))
{
Debug.WriteLine("文件不存在创建空文件");
// 获取不带文件名的目录路径
string directoryPath = Path.GetDirectoryName(allCommunicatorsConnectionStringPath);
SaveAllCommunicators();
return true;
}
string strJson = string.Empty;
using (StreamReader streamReader = new StreamReader(allCommunicatorsConnectionStringPath, Encoding.UTF8))
{
strJson = streamReader.ReadToEnd();
streamReader.Close();
}
GlobalVar.allCommunicatorsConnectionString = JsonConvert.DeserializeObject>(strJson);
if (GlobalVar.allCommunicatorsConnectionString == null)
{
MessageBox.Show("通讯端口加载失败!", "异常");
return false;
}
//清空通讯口会把所有通讯口断开连接
GlobalVar.dicCommunicators.Clear();
ConcurrentDictionary clientsCommunicatorsConnectionString = new ConcurrentDictionary();
foreach (var CommunicatorConnectionString in GlobalVar.allCommunicatorsConnectionString)
{
string CommunicatorName = CommunicatorConnectionString.Key;
string CommunicatorAddress = CommunicatorConnectionString.Value;
// 定义正则表达式以提取协议、IP 地址和端口
//1. \((.*?)\):\(和 \) 是用于匹配括号的转义字符。
// (.*?) 是一个非贪婪的匹配,用来匹配类名(MyProcesses.Communicators.TCPServer 或 MyProcesses.Communicators.UARTPort)。
//2. ([^:] +):匹配冒号之前的部分,即地址(127.0.0.1 或 COM5)。这里使用了[^:] 来匹配除了冒号之外的任意字符。
//3. (\d +) :匹配端口号,确保它匹配一个或多个数字。
string pattern = @"^\((?[^)]+)\)\[(?[^]]+)\]\[(?[^]]+)\]$";
Match match = Regex.Match(CommunicatorAddress, pattern);
if (match.Success)
{
string ClassName = match.Groups["ClassName"].Value; // "TCP"
string IP = match.Groups["IP"].Value; // "127.0.0.1"
string PORT = match.Groups["PORT"].Value; // "1111"
if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
break;
//利用反射创建实例
Type type = IProcess.GetExecutingAssembly().GetType(ClassName);
if (type == null)
{
Debug.WriteLine("Class not found.");
return false;
}
var Communicator = Activator.CreateInstance(type, CommunicatorName) as BaseCommunicator;
if (Communicator == null)
{
Debug.WriteLine("BaseCommunicator not found.");
return false;
}
//TCP客户端最后再连接
if (Communicator is TCPClient)
{
clientsCommunicatorsConnectionString.TryAdd(CommunicatorConnectionString.Key, CommunicatorConnectionString.Value);
continue;
}
Communicator.CommunicatorConnections.Add("地址", IP);
Communicator.CommunicatorConnections.Add("端口", PORT);
Communicator.CommunicatorName = CommunicatorName;
if (!Communicator.Connect())
{
LogInfo($"初始化通讯口[{CommunicatorName}]失败,原因是{Communicator.Msg}", LogInfoType.ERROR);
}
else
{
LogInfo($"初始化通讯口[{CommunicatorName}]成功", LogInfoType.PASS);
}
GlobalVar.dicCommunicators.TryAdd(CommunicatorName, Communicator);
}
else
{
Debug.WriteLine("No match found.");
}
}
//TCP客户端最后连接
foreach (var CommunicatorConnectionString in clientsCommunicatorsConnectionString)
{
string CommunicatorName = CommunicatorConnectionString.Key;
string CommunicatorAddress = CommunicatorConnectionString.Value;
// 定义正则表达式以提取协议、IP 地址和端口
//1. \((.*?)\):\(和 \) 是用于匹配括号的转义字符。
// (.*?) 是一个非贪婪的匹配,用来匹配类名(MyProcesses.Communicators.TCPServer 或 MyProcesses.Communicators.UARTPort)。
//2. ([^:] +):匹配冒号之前的部分,即地址(127.0.0.1 或 COM5)。这里使用了[^:] 来匹配除了冒号之外的任意字符。
//3. (\d +) :匹配端口号,确保它匹配一个或多个数字。
var regex = new Regex(@"^\((?[^)]+)\)\[(?[^]]+)\]\[(?[^]]+)\]$");
var match = regex.Match(CommunicatorAddress);
if (match.Success)
{
string ClassName = match.Groups[1].Value; // "TCP"
string IP = match.Groups[2].Value; // "127.0.0.1"
string PORT = match.Groups[3].Value; // "1111"
if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
{
break;
}
//利用反射创建实例
Type type = IProcess.GetExecutingAssembly().GetType(ClassName);
if (type == null)
{
Debug.WriteLine("Class not found.");
return false;
}
var Communicator = Activator.CreateInstance(type, CommunicatorName) as BaseCommunicator;
if (Communicator == null)
{
Debug.WriteLine("BaseCommunicator not found.");
return false;
}
Communicator.CommunicatorConnections.Add("地址", IP);
Communicator.CommunicatorConnections.Add("端口", PORT);
Communicator.CommunicatorName = CommunicatorName;
if (!Communicator.Connect())
{
LogInfo($"初始化通讯口[{CommunicatorName}]失败,原因是{Communicator.Msg}", LogInfoType.ERROR);
}
else
{
LogInfo($"初始化通讯口[{CommunicatorName}]成功", LogInfoType.PASS);
}
GlobalVar.dicCommunicators.TryAdd(CommunicatorName, Communicator);
}
else
{
Debug.WriteLine("No match found.");
}
}
return true;
}
catch { return false; }
}
public bool SaveAllCommunicators()
{
try
{
string strJson = string.Empty;
GlobalVar.allCommunicatorsConnectionString = new ConcurrentDictionary();
foreach (var item in GlobalVar.dicCommunicators)
{
string ClassName = item.Value.GetType().FullName;// "TCP"
string IP = item.Value.CommunicatorConnections["地址"].ToString();//"127.0.0.1"
string PORT = item.Value.CommunicatorConnections["端口"].ToString();//"1111"
if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT))
{
break;
}
string CommunicatorConnectionString = $"({ClassName})[{IP}][{PORT}]";
GlobalVar.allCommunicatorsConnectionString.TryAdd(item.Key, CommunicatorConnectionString);
}
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
// 自定义缩进(4空格)
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
strJson = JsonConvert.SerializeObject(GlobalVar.allCommunicatorsConnectionString, settings);
//判断文件夹是否存在,防呆输入为文件名称
string directoryPath = Path.GetDirectoryName(GlobalVar.allCommunicatorsConnectionStringPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch (Exception)
{ }
}
File.WriteAllText(GlobalVar.allCommunicatorsConnectionStringPath, strJson, Encoding.UTF8);
return true;
}
catch { return false; }
}
public bool LoadAllProcess(string allProcessConnectionStringPath)
{
try
{
if (!File.Exists(allProcessConnectionStringPath))
{
Debug.WriteLine("文件不存在创建空文件");
// 获取不带文件名的目录路径
string directoryPath = Path.GetDirectoryName(allProcessConnectionStringPath);
SaveAllProcess();
return true;
}
string strJson = string.Empty;
using (StreamReader streamReader = new StreamReader(allProcessConnectionStringPath, Encoding.UTF8))
{
strJson = streamReader.ReadToEnd();
streamReader.Close();
}
List lstProcessName = JsonConvert.DeserializeObject>(strJson);
if (lstProcessName == null)
{
return false;
}
// 使用方式
var sortedKeys = lstProcessName
.OrderBy(k => k, new NaturalStringComparer())
.ToList();
GlobalVar.dicProcesses.Clear();
foreach (var ProcessName in sortedKeys)
{
GlobalVar.dicProcesses.TryAdd(ProcessName
, new ProcessRunBll(ProcessName, GlobalVar.dicCameras, GlobalVar.dicCommunicators));
}
return true;
}
catch { return false; }
}
public bool SaveAllProcess()
{
try
{
string strJson = string.Empty;
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
// 自定义缩进(4空格)
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
strJson = JsonConvert.SerializeObject(GlobalVar.dicProcesses.Keys.ToList(), settings);
//判断文件夹是否存在,防呆输入为文件名称
string directoryPath = Path.GetDirectoryName(GlobalVar.allProcessConnectionStringPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch { }
}
File.WriteAllText(GlobalVar.allProcessConnectionStringPath, strJson, Encoding.UTF8);
foreach (var process in GlobalVar.dicProcesses.Values)
{
if (!process.Save(out string msg))
{
LogInfo($"流程[{process.Name}]保存失败,原因:{msg}", LogInfoType.NOSHOW);
}
}
try
{
string json = JsonConvert.SerializeObject(GlobalVar.ControlStates, settings);
File.WriteAllText(GlobalVar.allRunSettingStringPath, json);
LogInfo($"流程运行设置保存成功", LogInfoType.INFO);
}
catch { }
return true;
}
catch { return false; }
}
public bool LoadAllProcessVars(string allProcessVarsPath)
{
try
{
if (!File.Exists(allProcessVarsPath))
{
Debug.WriteLine("文件不存在创建空文件");
// 获取不带文件名的目录路径
string directoryPath = Path.GetDirectoryName(allProcessVarsPath);
SaveAllProcessVars();
return true;
}
string strJson = string.Empty;
using (StreamReader streamReader = new StreamReader(allProcessVarsPath, Encoding.UTF8))
{
strJson = streamReader.ReadToEnd();
streamReader.Close();
}
IProcess.dicGlobalVars.Clear();
IProcess.dicGlobalVars = JsonConvert.DeserializeObject>(strJson);
if (IProcess.dicGlobalVars == null)
{
IProcess.dicGlobalVars = new ConcurrentDictionary();
return false;
}
return true;
}
catch { return false; }
}
public bool SaveAllProcessVars()
{
try
{
string strJson = string.Empty;
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
// 自定义缩进(4空格)
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
}
};
strJson = JsonConvert.SerializeObject(IProcess.dicGlobalVars, settings);
//判断文件夹是否存在,防呆输入为文件名称
string directoryPath = Path.GetDirectoryName(GlobalVar.allProcessVarsPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch { }
}
File.WriteAllText(GlobalVar.allProcessVarsPath, strJson, Encoding.UTF8);
LogInfo($"全局变量保存成功", LogInfoType.INFO);
strJson = JsonConvert.SerializeObject(GlobalVar.dicLayout, settings);
//判断文件夹是否存在,防呆输入为文件名称
directoryPath = Path.GetDirectoryName(GlobalVar.allLayoutPath);
if (!Directory.Exists(directoryPath))
{
try
{
Directory.CreateDirectory(directoryPath);
}
catch { }
}
File.WriteAllText(GlobalVar.allLayoutPath, strJson, Encoding.UTF8);
LogInfo($"全局布局保存成功", LogInfoType.INFO);
return true;
}
catch { return false; }
}
public bool LoadAllLayout(string allLayoutPath)
{
try
{
if (!File.Exists(allLayoutPath))
{
Debug.WriteLine("文件不存在创建空文件");
AsyncLogHelper.Info("文件不存在创建空文件");
// 获取不带文件名的目录路径
string directoryPath = Path.GetDirectoryName(allLayoutPath);
SaveAllLayout();
return true;
}
string strJson = string.Empty;
using (StreamReader streamReader = new StreamReader(allLayoutPath, Encoding.UTF8))
{
strJson = streamReader.ReadToEnd();
streamReader.Close();
}
GlobalVar.dicLayout.Clear();
GlobalVar.dicLayout = JsonConvert.DeserializeObject>(strJson);
if (GlobalVar.dicLayout == null)
{
GlobalVar.dicLayout = new ConcurrentDictionary();
return false;
}
return true;
}
catch { return false; }
}
private void btn_GlobalVar_Click(object sender, EventArgs e)
{
GlobalVarForm globalVarForm = new GlobalVarForm(GlobalVar.allProcessVarsPath);
globalVarForm.ShowDialog();
}
private void btn_Login_Click(object sender, EventArgs e)
{
//this.Hide();
//MainWindow.InstanceLoginandConfirmation().ShowDialog();
//if (!MainWindow.InstanceLoginandConfirmation().isQuit && MainWindow.InstanceLoginandConfirmation().correctUser)
//{
// MainWindow.InstanceLoginandConfirmation().closeLoginFrm();
// if (UserManager.Instance.CurrentUser.EmployeePermission == UserPermission.Operator)
// {
// //操作员权限界面
// }
// else if (UserManager.Instance.CurrentUser.EmployeePermission == UserPermission.Engineer)
// {
// //技术员权限界面
// }
// else if (UserManager.Instance.CurrentUser.EmployeePermission == UserPermission.Administrator)
// {
// //管理员权限界面
// }
// this.Show();
//}
}
private void com_ProductName_SelectedValueChanged(object sender, EventArgs e)
{
if (com_ProductName.SelectedItem == null || com_ProductName.SelectedItem?.ToString() == GlobalVar.strProductName)
{
return;
}
if (com_ProductName.SelectedItem?.ToString() == "新增")
{
using (CreateProductForm createDatabaseForm = new CreateProductForm())
{
createDatabaseForm.ShowDialog();
}
}
else
{
//变更前保存现有配置
SaveAllSetting();
LogInfo($"产品从{GlobalVar.strProductName}切换{com_ProductName.SelectedItem?.ToString()}", LogInfoType.WARN);
//Tool.WriteConfig("数据库名称", com_ProductName.SelectedItem?.ToString());
GlobalVar.strProductName = com_ProductName.SelectedItem?.ToString();
foreach (BaseCamera camera in GlobalVar.dicCameras.Values)
{
camera.Dispose();
}
GlobalVar.dicCameras.Clear();
foreach (BaseCommunicator communicator in GlobalVar.dicCommunicators.Values)
{
communicator.TriggerRunMessageReceived -= TriggerRunMessageReceived;
communicator.Disconnect();
}
GlobalVar.dicCommunicators.Clear();
//保存完现有配置后断开所有事件
foreach (var Process in GlobalVar.dicProcesses.Values)
{
Process.LogInfo -= LogInfo;
}
GlobalVar.dicProcesses.Clear();
//重新加载配置
this.VisionForm_Load(sender, e);
}
}
private void TriggerRunMessageReceived(string name, string msg)
{
if (msg == null || msg.Trim('\0', '\r', '\n', ' ', '\uFEFF') == "" || string.IsNullOrEmpty(msg))
{
return;
}
LogInfo(string.Format("通讯[{0}]接收到的消息\"{1}\"", name, msg), LogInfoType.INFO);
var matchedItems = GlobalVar.dicProcessSetting
.Where(item =>
{
var value = item.Value;
var triggerComm = value["触发通讯"];
var triggerChar = value["触发字符"];
return triggerComm != null && triggerComm.Equals(name) &&
(string.IsNullOrEmpty(triggerChar?.ToString()) ||
msg.StartsWith(triggerChar.ToString()));
})
.ToList(); // 避免重复字典访问和装箱操作
if (matchedItems.Count <= 0)
{
return;
}
if (!ckb_AllowRun.Checked)
{
LogInfo(string.Format($"检查到可被触发的流程,当前不为运行模式!"), LogInfoType.ERROR);
return;
}
GlobalVar.dicProcesses.Values.AsParallel().ForAll(v => v.bCompleted = false);
LogInfo(string.Format($"检查到可被触发的流程,清空所有流程运行完成标记位!"), LogInfoType.INFO);
Parallel.ForEach(matchedItems, item =>
{
string ProcessName = item.Value["流程名"];
LogInfo($"流程[{ProcessName}]开始运行", LogInfoType.INFO);
if (!GlobalVar.dicProcesses.ContainsKey(ProcessName))
{
LogInfo(string.Format("流程[{0}]不存在,请检查流程设置", ProcessName), LogInfoType.ERROR);
return;
}
ProcessRunBll RunBll = GlobalVar.dicProcesses[ProcessName];
if (RunBll == null || RunBll.bRuning)
{
LogInfo(string.Format("流程[{0}]上次未运行完成,触发失败", ProcessName)
, LogInfoType.ERROR);
return;
}
try
{
bool result = false;
string msg = string.Empty;
int times = Convert.ToInt32(item.Value["重测次数"].ToString());
string ConnecResult = item.Value["关联结果"];
if (times < 0)
{
result = GlobalVar.dicProcesses[ProcessName].Run();
msg = GlobalVar.dicProcesses[ProcessName].Msg;
if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
{
GlobalVar.dicProcesses[ProcessName].GetBooleanOutput(ConnecResult, out result);
GlobalVar.dicProcesses[ProcessName].Result = result;
}
if (!result)
{
LogInfo($"流程[{ProcessName}]被强制运行成功", LogInfoType.WARN);
GlobalVar.dicProcesses[ProcessName].Result = true;
result = true;
}
}
else
{
while (times >= 0)
{
result = RunBll.Run();
msg = RunBll.Msg;
if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联"))
{
RunBll.GetBooleanOutput(ConnecResult, out result);
RunBll.Result = result;
}
if (result)
{
break;
}
else if (!result && times > 0)
{
LogInfo(string.Format("流程[{0}]运行失败重新测试,剩余次数[{1}]", ProcessName, times), LogInfoType.WARN);
}
times--;
}
}
string ConnectProcess = item.Value["关联流程"];
if (!(ConnectProcess == null || string.IsNullOrEmpty(ConnectProcess) || ConnectProcess.Trim() == ""))
{
//用逗号或者分号去间隔关联流程
string[] arrConnectProcess;
if (ConnectProcess.Split(';').Length >= ConnectProcess.Split(',').Length)
{
arrConnectProcess = ConnectProcess.Split(';');
}
else
{
arrConnectProcess = ConnectProcess.Split(',');
}
foreach (string strConnectProcess in arrConnectProcess)
{
if (GlobalVar.dicProcesses.ContainsKey(strConnectProcess))
{
ProcessRunBll ConnectRunBll = GlobalVar.dicProcesses[strConnectProcess];
int waitTime = 10;
DateTime startTime = DateTime.Now;
while ((DateTime.Now - startTime).TotalSeconds < waitTime
&& (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted))
{
LogInfo(string.Format("关联流程[{0}]未运行完成,剩余等待[{1}]s", strConnectProcess, (waitTime - ((DateTime.Now - startTime).TotalSeconds)))
, LogInfoType.NOSHOW);
Thread.Sleep(1000);
continue;
}
if (ConnectRunBll.bRuning || !ConnectRunBll.bCompleted)
{
GlobalVar.dicProcesses[ProcessName].Msg = string.Format("流程[{0}]未运行完成", ProcessName);
LogInfo(string.Format("关联流程[{0}]未运行完成", strConnectProcess), LogInfoType.ERROR);
result = false;
break;
}
else if (!ConnectRunBll.bRuning && ConnectRunBll.bCompleted)
{
LogInfo(string.Format("关联流程[{0}]运行完成", strConnectProcess), LogInfoType.INFO);
}
result &= ConnectRunBll.Result;
if (!ConnectRunBll.Result)
{
LogInfo($"流程[{ProcessName}]的关联流程[{strConnectProcess}]运行失败", LogInfoType.ERROR);
msg = $"关联流程[{strConnectProcess}]运行失败";
}
}
}
}
LogInfo(result ? $"流程[{ProcessName}]运行成功" : $"流程[{ProcessName}]运行失败,原因是{msg}", result ? LogInfoType.PASS : LogInfoType.ERROR);
string SendComName = result ? item.Value["成功通讯"] : item.Value["失败通讯"];
string SendMsg = result ? item.Value["成功字符"] : item.Value["失败字符"];
if (GlobalVar.dicCommunicators.ContainsKey(SendComName) && (!string.IsNullOrEmpty(SendMsg) || SendMsg.Trim() != ""))
{
GlobalVar.dicCommunicators[SendComName].SendMessage(SendMsg);
LogInfo(string.Format("发送给[{0}]了消息\"{1}\"", SendComName, SendMsg), LogInfoType.INFO);
}
}
catch (Exception ex)
{
LogInfo(string.Format("流程[{0}]运行发生了意外,原因是:{1}", ProcessName, ex.Message + $"【{ex.StackTrace}】"), LogInfoType.ERROR);
RunBll.Result = false;
RunBll.Msg = $"[意外]{ex.Message}";
}
finally
{
#region 从RunSettingPage和Layout中获取是否保存图片
string strImageType = "jpeg";
bool bSaveRunImage = false;
bool bSaveResultImage = false;
long lImageQuality = 100L;
//ckbSaveRunImage
if (GlobalVar.ControlStates.TryGetValue("ckbSaveRunImage_CheckBox", out object oSaveRunImage))
{
if (oSaveRunImage != null && oSaveRunImage is bool)
{
bSaveRunImage = (bool)oSaveRunImage;
}
}
//ckbSaveResultImage
if (GlobalVar.ControlStates.TryGetValue("ckbSaveResultImage_CheckBox", out object oSaveResultImage))
{
if (oSaveResultImage != null && oSaveResultImage is bool)
{
bSaveResultImage = (bool)oSaveResultImage;
}
}
//txtImageQuality
if (GlobalVar.ControlStates.TryGetValue("txtImageQuality_TextBox", out object oImageQuality))
{
if (oImageQuality != null && oImageQuality is string)
{
lImageQuality = Convert.ToInt64((string)oImageQuality);
}
}
//cmbImageType
if (GlobalVar.ControlStates.TryGetValue("cmbImageType_ComboBox", out object oImageType))
{
try
{
// 动态解析ComboBox数据
var json = JsonConvert.SerializeObject(oImageType);
var comboData = JsonConvert.DeserializeAnonymousType(json, new
{
Items = new List