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.SiemensS7; 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.dicCameras.DictionaryChanged += CamerasChanged; 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) { try { switch (e.ChangeType) { case DictionaryChangeType.Added: e.NewValue.TriggerRunMessageReceived += TriggerRunMessageReceived; LogInfo($"通讯口[{e.NewValue.CommunicatorName}]加载触发通讯", LogInfoType.INFO); e.NewValue.CommunicatorName = e.NewKey; break; case DictionaryChangeType.Renamed: string OldCommunicatorName = e.OldKey; string NewCommunicatorName = e.NewKey; LogInfo(string.Format("重命名通讯口名[{0}]修改为[{1}]", OldCommunicatorName, NewCommunicatorName), LogInfoType.INFO); e.NewValue.CommunicatorName = NewCommunicatorName; break; case DictionaryChangeType.Removed: if (e.OldValue != null && e.OldValue is BaseCommunicator) e.OldValue.Disconnect(); e.OldValue.TriggerRunMessageReceived -= TriggerRunMessageReceived; LogInfo($"通讯口[{e.OldValue.CommunicatorName}]移除触发通讯", LogInfoType.INFO); break; } } catch { } } 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 CamerasChanged(object sender, DictionaryChangedEventArgs e) { try { switch (e.ChangeType) { case DictionaryChangeType.Added: e.NewValue.TriggerRunMessageReceived += TriggerRunMessageReceived; LogInfo($"相机[{e.NewValue.SN}]加载触发通讯", LogInfoType.INFO); e.NewValue.SN = e.NewKey; break; case DictionaryChangeType.Removed: if (e.OldValue != null && e.OldValue is BaseCommunicator) e.OldValue.CloseDevice(); e.OldValue.TriggerRunMessageReceived -= TriggerRunMessageReceived; LogInfo($"相机[{e.OldValue.SN}]移除触发通讯", LogInfoType.INFO); break; } } catch { } } 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, IntPtr.Zero)) { 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; if (!string.IsNullOrEmpty(CommunicatorAddress) && CommunicatorAddress.Contains("SiemensLBS7")) { // 定义正则表达式以提取协议、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 Slot = match.Groups["Slot"].Value; // "1111" string CpuType= match.Groups["CpuType"].Value; string PlcAddress = match.Groups["PlcAddress"].Value; if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(Slot) || string.IsNullOrEmpty(CpuType) || string.IsNullOrEmpty(PlcAddress)) 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("端口", Slot); Communicator.CommunicatorConnections.Add("型号", CpuType); Communicator.CommunicatorConnections.Add("变量地址", PlcAddress); 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."); } } else { // 定义正则表达式以提取协议、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) && ClassName.Contains("SiemensLBS7")) { string CpuType = item.Value.CommunicatorConnections["型号"].ToString(); string PlcAddress = item.Value.CommunicatorConnections["变量地址"].ToString(); if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT) || string.IsNullOrEmpty(CpuType) || string.IsNullOrEmpty(PlcAddress)) { break; } string CommunicatorConnectionString = $"({ClassName})[{IP}][{PORT}][{CpuType}][{PlcAddress}]"; GlobalVar.allCommunicatorsConnectionString.TryAdd(item.Key, CommunicatorConnectionString); } else { 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(), SelectedIndex = 0 }); if (comboData != null && comboData.Items.Count > 0) { strImageType = comboData.Items[comboData.SelectedIndex].ToString(); } } catch { } } // 生成图片并显示到控件中 HObject InputImage = null; HObject RecordImage = null; foreach (var layout in GlobalVar.dicLayout.Values .Where(layout => layout.ProcessName == ProcessName) .ToList()) { string title = layout.Title; string strImagePath = layout.SaveImageDir; if (!AllProcessesPages.dicProcessControls.ContainsKey(title)) { continue; } RunBll.GetImage(layout, out InputImage, out RecordImage); AllProcessesPages.dicProcessControls[title].ShowHoImage(RecordImage); if (!string.IsNullOrEmpty(layout.SaveImageDir)) { string fileNameHead = layout.SaveImageHead; string result = Regex.Replace(fileNameHead, @"\{[^}]+\}", match => { // 去除{}只保留括号内的内容 string content = match.Value; content = content.Trim('{', '}'); // 去除首尾的{} RunBll.GetStringOutput(content, out string str); return str; }); string fileName = $"{result}-[{DateTime.Now.ToString("HH.mm.ss.ffff")}]"; // 使用正则表达式替换所有非法字符 string invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars())); string pattern = $"[{invalidChars}]"; fileName = Regex.Replace(fileName, pattern, "-"); strImagePath = Regex.Replace(strImagePath, @"\{[^}]+\}", match => { // 去除{}只保留括号内的内容 string content = match.Value; content = content.Trim('{', '}'); // 去除首尾的{} RunBll.GetStringOutput(content, out string str); return str; }); if (bSaveRunImage) { // 最后一级目录必须为年月日,会根据时间来删除旧图片 string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\原图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\"); LB_SmartVision.Tool.Tool.AddRealImage(InputImage, directoryPath, fileName, strImageType, lImageQuality); } if (bSaveResultImage) { // 最后一级目录必须为年月日,会根据时间来删除旧图片 string directoryPath = Path.Combine(strImagePath, $"{ProcessName}\\截图\\{RunBll.Result}\\{DateTime.Now.ToString("yyyyMMdd")}\\"); LB_SmartVision.Tool.Tool.AddRealImage(RecordImage, directoryPath, fileName, "jpg", 50L); } } } foreach (var csv in GlobalVar.dicCsvSetting.Values .Where(csv => csv.ProcessName == ProcessName) .ToList()) { if (RunBll.GetCsv(csv , out List DataTitle, out Dictionary ResultData)) { string filePath = Path.Combine(GlobalVar.strPathCsv, $"{ProcessName}.csv"); LB_SmartVision.Tool.Tool.SaveData(filePath, DataTitle, ResultData); } } #endregion } }); } private void VisionForm_FormClosing(object sender, FormClosingEventArgs e) { SaveAllSetting(); if (MessageBox.Show("是否关闭软件?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK)// { e.Cancel = true; return; } //关闭窗体释放资源 AsyncLogHelper.Dispose(); foreach (BaseCamera camera in GlobalVar.dicCameras.Values) { camera.Dispose(); } foreach (BaseCommunicator communicator in GlobalVar.dicCommunicators.Values) { communicator.Disconnect(); } FormClosing -= VisionForm_FormClosing; } } }