using HalconDotNet; using LB_SmartVision.Forms; using LB_SmartVision.Forms.Pages; using LB_SmartVision.Forms.Pages.BarcodeReaderPage; using LB_SmartVision.Forms.Pages.CameraPage; using LB_SmartVision.Forms.Pages.CommunicatorPage; using LB_SmartVision.Forms.Pages.HistoricalData; using LB_SmartVision.Forms.Pages.LEDLightSourceControlPage; 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.SQL; using LB_SmartVision.Tool; using LB_SmartVisionCommon; using LB_SmartVisionLoginUI; using LB_VisionProcesses; using LB_VisionProcesses.BarcodeReaders; using LB_VisionProcesses.BarcodeReaders.Huayray; using LB_VisionProcesses.Cameras; using LB_VisionProcesses.Cameras.HikCameras; using LB_VisionProcesses.Cameras.HRCameras; using LB_VisionProcesses.Cameras.LBCameras; using LB_VisionProcesses.Cameras.LocalCameras; using LB_VisionProcesses.Cameras.MicroCameras; using LB_VisionProcesses.Cameras.MindCameras; 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 Serilog; using Serilog.Events; 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 { #region Variable public string NowBom = string.Empty; AllProcessesPage AllProcessesPage = new AllProcessesPage(); CamerasEditPage CamerasEditPage = new CamerasEditPage(); BarcodeReadersEditPage BarcodeReadersEditPage = new BarcodeReadersEditPage(); HistoricalDataEditPage HistoricalDataEditPage = new HistoricalDataEditPage(); CommunicatorsEditPage CommunicatorsEditPage = new CommunicatorsEditPage(); SettingEditPage SettingEditPage = new SettingEditPage(); MESEditPage MESEditPage = new MESEditPage(); MotionControlEditPage MotionControlEditPage = new MotionControlEditPage(); UserManagementEditPage UserManagementEditPage = new UserManagementEditPage(); LEDLightSourceControlEditPage lEDLightSourceControlEditPage = new LEDLightSourceControlEditPage(); byte[] Assembly_LB_VisionProcessesBytes = File.ReadAllBytes("LB_VisionProcesses.dll"); /// /// 用于反序列化的程序集引用 /// Assembly Assembly_LB_VisionProcessesDll = null; //string LogFilePath(string LogEvent) => $"{GlobalVar.strPathLog}\\{LogEvent}.log"; //string SerilogOutputTemplate = "{NewLine}{NewLine}Date:{Timestamp:yyyy-MM-dd HH:mm:ss.fff}{NewLine}LogLevel:{Level}{NewLine}Message:{Message}{NewLine}{Exception}" + new string('-', 50); // 窗体类的全局变量:标记是否允许切换Tab(默认允许) private bool _isTabSwitchAllowed = true; #endregion 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(); AllProcessesPage.controlsPanel.Dock = DockStyle.Fill; materialTabControl.Controls.Add(AllProcessesPage); HistoricalDataEditPage.LogInfo += LogInfo; materialTabControl.Controls.Add(new MyPage(HistoricalDataEditPage)); lEDLightSourceControlEditPage.LogInfo += LogInfo; materialTabControl.Controls.Add(new MyPage(lEDLightSourceControlEditPage)); CamerasEditPage.LogInfo += LogInfo; materialTabControl.Controls.Add(new MyPage(CamerasEditPage)); BarcodeReadersEditPage.LogInfo += LogInfo; materialTabControl.Controls.Add(new MyPage(BarcodeReadersEditPage)); CommunicatorsEditPage.LogInfo += LogInfo; materialTabControl.Controls.Add(new MyPage(CommunicatorsEditPage)); SettingEditPage.LogInfo += LogInfo; SettingEditPage.OnRemoveSettingPage += SettingEditPage_OnRemoveSettingPage; 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", 12F, FontStyle.Regular, GraphicsUnit.Point, 0); materialTabControl.TabPages[i].ForeColor = Color.White; } materialTabSelector.BaseTabControl = materialTabControl; //materialTabSelector.Font = new Font("Microsoft YaHei UI", 18F, FontStyle.Regular, GraphicsUnit.Point, 0); //Log.Logger = new LoggerConfiguration() // .MinimumLevel.Debug() // 所有Sink的最小记录级别 // .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Debug).WriteTo.File(LogFilePath("Log"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)) // .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Information).WriteTo.File(LogFilePath("Log"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)) // .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Warning).WriteTo.File(LogFilePath("Log"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)) // .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Error).WriteTo.File(LogFilePath("Error"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)) // .WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == LogEventLevel.Fatal).WriteTo.File(LogFilePath("Log"), rollingInterval: RollingInterval.Day, outputTemplate: SerilogOutputTemplate)) // .CreateLogger(); // 初始化下拉框(假设已放置并正确命名为 materialCombobox1) //materialCombobox1.Visible = false; // 默认隐藏 materialCombobox1.SelectedIndexChanged += MaterialCombobox1_SelectedIndexChanged; // 监听 TabControl 的变化 materialTabControl.ControlAdded += (s, e) => UpdateOverflowComboBox(); materialTabControl.ControlRemoved += (s, e) => UpdateOverflowComboBox(); //HOperatorSet.SetSystem("max_mem_cache", 2048); } string removeName = string.Empty; private void SettingEditPage_OnRemoveSettingPage(string name) { removeName = name; if (materialCombobox1.Items.Contains(removeName)) { materialCombobox1.Items.Remove(removeName); materialCombobox1.SelectedItem = materialTabControl.SelectedTab.Text; } } private int CalculateTotalTabWidth() { // 简单估算:每个选项卡宽度 = 文本宽度 + 内边距(可根据实际调整) int total = 0; using (Graphics g = materialTabControl.CreateGraphics()) { foreach (TabPage page in materialTabControl.TabPages) { SizeF textSize = g.MeasureString(page.Text, materialTabControl.Font); total += (int)textSize.Width + 32; // 32 为左右内边距估计值 } } return total; } private void UpdateOverflowComboBox() { // 判断是否溢出的逻辑(参考上一轮回复中的 CalculateTotalTabWidth 方法) bool overflow = CalculateTotalTabWidth() > materialTabControl.Width; //materialCombobox1.Visible = overflow; //if (overflow) //{ // materialCombobox1.Items.Clear(); // foreach (TabPage page in materialTabControl.TabPages) // { // // 使用正确的控件,添加项的方式不变 // materialCombobox1.Items.Add(page.Text); // } // // 可选:默认选中当前项 // materialCombobox1.SelectedItem = materialTabControl.SelectedTab.Text; //} materialCombobox1.Items.Clear(); foreach (TabPage page in materialTabControl.TabPages) { // 使用正确的控件,添加项的方式不变 if (/*!string.IsNullOrEmpty(removeName) && */!removeName.Equals(page.Text)) { materialCombobox1.Items.Add(page.Text); } } // 可选:默认选中当前项 materialCombobox1.SelectedItem = materialTabControl.SelectedTab.Text; } private void MaterialCombobox1_SelectedIndexChanged(object sender, EventArgs e) { if (materialCombobox1.SelectedItem != null) { string selectedText = materialCombobox1.SelectedItem.ToString(); // 查找并切换选项卡 foreach (TabPage page in materialTabControl.TabPages) { if (page.Text == selectedText) { materialTabControl.SelectedTab = page; break; } } } } 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 > 500) { 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 = { @"Log\Run", @"Log\Debug", @"Log\Error", @"Log\Fatal", @"Log\Warn", }; foreach (string path in paths) { EnsureDirectory(path); } if (!LB_SmartVision.Tool.Tool.ReadStringConfig("数据库名称", out string DateBaseName)) { DateBaseName = "Product0"; 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); } //加载读码器 foreach (var reader in GlobalVar.dicBarcodeReaders.Values) { reader.Dispose(); } GlobalVar.dicBarcodeReaders.Clear(); if (LoadAllBarcodeReaders(GlobalVar.allBarcodeReadersConnectionStringPath)) { LogInfo("读码器加载成功", LogInfoType.PASS); } else { LogInfo("读码器加载失败", LogInfoType.ERROR); } //加载全局变量 IProcess.dicGlobalVars.Clear(); if (LoadAllProcessVars(GlobalVar.allProcessVarsPath)) { LogInfo("全局变量加载成功", LogInfoType.PASS); } else { LogInfo("全局变量加载失败", LogInfoType.ERROR); } //加载运行控制参数配置 GlobalVar.dicMotionControlData.Clear(); if (LoadMotionControlDatas(GlobalVar.allMotionControlDataPath)) { LogInfo("运动控制参数加载成功", LogInfoType.PASS); } else { LogInfo("运ca动控制参数加载失败", LogInfoType.ERROR); } //加载LED光源控制器参数配置 GlobalVar.dicSerialPort.Clear(); if (LoadSerialPorts(GlobalVar.AllSerialPortPath)) { 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); } //发送LED串口通讯 #region 发送LED串口通讯 if (GlobalVar.dicSerialPort != null && GlobalVar.dicSerialPort.Count > 0) { LEDControlSerialPort lEDControlSerialPort = new LEDControlSerialPort(); foreach (var item in GlobalVar.dicSerialPort.Keys) { lEDControlSerialPort.LEDControlParams = GlobalVar.dicSerialPort[item]; lEDControlSerialPort.OpenPort(); if (lEDControlSerialPort.serialPort.IsOpen) { foreach (var itemCH in GlobalVar.dicSerialPort[item].SendData.Keys) { switch (itemCH) { case "CH1": { lEDControlSerialPort.serialPort.Write(GlobalVar.dicSerialPort[item].SendData[itemCH]); break; } case "CH2": { lEDControlSerialPort.serialPort.Write(GlobalVar.dicSerialPort[item].SendData[itemCH]); break; } case "CH3": { lEDControlSerialPort.serialPort.Write(GlobalVar.dicSerialPort[item].SendData[itemCH]); break; } case "CH4": { lEDControlSerialPort.serialPort.Write(GlobalVar.dicSerialPort[item].SendData[itemCH]); break; } default: { break; } } Thread.Sleep(50); } } lEDControlSerialPort.ClosePort(); Thread.Sleep(100); } } #endregion //发送运动控制参数 #region 发送运动控制参数 if (GlobalVar.dicMotionControlData != null && GlobalVar.dicMotionControlData.Count > 0 && GlobalVar.dicMotionControlData.ContainsKey(GlobalVar.strProductName)) { foreach (var item in GlobalVar.dicMotionControlData[GlobalVar.strProductName].Keys) { if (GlobalVar.dicCommunicators.Keys.Contains("通讯0")) { SiemensLBS7 siemensLBS7 = GlobalVar.dicCommunicators["通讯0"] as SiemensLBS7; siemensLBS7.Write(GlobalVar.dicMotionControlData[GlobalVar.strProductName][item].XAxisAddress, GlobalVar.dicMotionControlData[GlobalVar.strProductName][item].XAxisAddress); } } } #endregion //显示所有产品 cmbProduct.Items.Clear(); LB_SmartVision.Tool.Tool.ReadStringConfig("产品列表", out string Products); List lstProduct = (Products.Split(',')).ToList(); foreach (string DatabaseName in lstProduct) { cmbProduct.Items.Add(DatabaseName); } cmbProduct.Items.Add("编辑"); cmbProduct.Text = GlobalVar.strProductName; this.WindowState = FormWindowState.Maximized; DatabaseRecordProductDataHelper.InitializeDatabase(); } public void SaveAllSetting() { SaveAllProcess(); SaveAllProcessVars(); SaveAllCommunicators(); SaveAllCameras(); SaveAllProcessSetting(); SaveAllLayout(); SaveAllCsv(); SaveMotionControlDatas(); SaveSerialPorts(); SaveAllBarcodeReaders(); } public bool LoadAllBarcodeReaders(string allBarcodeReadersConnectionStringPath) { if (!File.Exists(allBarcodeReadersConnectionStringPath)) { Debug.WriteLine("读码器配置文件不存在,创建空文件"); SaveAllBarcodeReaders(); return true; } string strJson = string.Empty; using (StreamReader streamReader = new StreamReader(allBarcodeReadersConnectionStringPath, Encoding.UTF8)) { strJson = streamReader.ReadToEnd(); streamReader.Close(); } GlobalVar.allBarcodeReadersConnectionString = JsonConvert.DeserializeObject>(strJson); if (GlobalVar.allBarcodeReadersConnectionString == null) { MessageBox.Show("读码器加载失败!", "异常"); return false; } BarcodeReaderBase reader = null; foreach (var ReaderConnectionString in GlobalVar.allBarcodeReadersConnectionString) { Enum.TryParse(ReaderConnectionString.Value, out BarcodeReaderBrand brand); switch (brand) { case BarcodeReaderBrand.Huayray: { reader = new HRBarcodeReader(); break; } default: { MessageBox.Show($"[{ReaderConnectionString.Key}]读码器品牌不支持!", "异常"); continue; } } reader.SN = ReaderConnectionString.Key; if (!reader.Open(ReaderConnectionString.Key)) { LogInfo($"初始化读码器[{ReaderConnectionString.Key}]失败", LogInfoType.ERROR); reader.IsConnected = false; reader.IsGrabbing = false; } else { LogInfo($"初始化读码器[{ReaderConnectionString.Key}]成功", LogInfoType.PASS); } GlobalVar.dicBarcodeReaders.TryAdd(ReaderConnectionString.Key, reader); } return true; } public bool SaveAllBarcodeReaders() { try { string strJson = string.Empty; GlobalVar.allBarcodeReadersConnectionString = new ConcurrentDictionary(); foreach (var item in GlobalVar.dicBarcodeReaders) { string ReaderSN = item.Value.SN; string ReaderBrand = item.Value.Brand.ToString(); if (string.IsNullOrEmpty(ReaderSN) || string.IsNullOrEmpty(ReaderBrand)) { break; } GlobalVar.allBarcodeReadersConnectionString.TryAdd(ReaderSN, ReaderBrand); } var settings = new JsonSerializerSettings { Formatting = Formatting.Indented, ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() } }; strJson = JsonConvert.SerializeObject(GlobalVar.allBarcodeReadersConnectionString, settings); string directoryPath = Path.GetDirectoryName(GlobalVar.allBarcodeReadersConnectionStringPath); if (!Directory.Exists(directoryPath)) { try { Directory.CreateDirectory(directoryPath); } catch (Exception) { } } File.WriteAllText(GlobalVar.allBarcodeReadersConnectionStringPath, strJson, Encoding.UTF8); return true; } catch { return false; } } public bool LoadSerialPorts(string allSerialPortPath) { try { GlobalVar.dicSerialPort = ConfigManager>.LoadConfig>(allSerialPortPath); } catch { return false; } return true; } public bool SaveSerialPorts() { try { ConfigManager>.SaveConfig>(GlobalVar.dicSerialPort, GlobalVar.AllSerialPortPath); } catch { return false; } return true; } public bool LoadMotionControlDatas(string alMotionControlDataPath) { try { GlobalVar.dicMotionControlData = ConfigManager>>.LoadConfig>>(alMotionControlDataPath); } catch { return false; } return true; } public bool SaveMotionControlDatas() { try { Dictionary> removeCameraSN = new Dictionary>(); foreach (var item in GlobalVar.dicMotionControlData.Keys) { List list = new List(); foreach (var itemSN in GlobalVar.dicMotionControlData[item].Keys) { if (!GlobalVar.dicCameras.Keys.Contains(itemSN)) { list.Add(itemSN); } } if (list.Count > 0) { removeCameraSN.TryAdd(item, list); } } foreach (var item in removeCameraSN.Keys) { foreach (var itemSN in removeCameraSN[item]) { //GlobalVar.dicMotionControlData[item]. GlobalVar.dicMotionControlData[item].Remove(itemSN); } } ConfigManager>>.SaveConfig>>(GlobalVar.dicMotionControlData, GlobalVar.allMotionControlDataPath); } catch { return false; } return true; } 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; } foreach (var CameraConnectionString in GlobalVar.allCamerasConnectionString) { BaseCamera camera = null; Enum.TryParse(CameraConnectionString.Value, out CameraBrand brand); switch (brand) { case CameraBrand.HRCamera: { camera = new HRCamera(); break; } case CameraBrand.LBCamera: { camera = new LBCamera(); break; } case CameraBrand.LocalCamera: { camera = new LocalCamera(); break; } case CameraBrand.HikCamera: { camera = new HikCamera(); break; } case CameraBrand.HikCodeReader: { camera = new HikCodeReader(); break; } case CameraBrand.MindCamera: { camera = new MindCamera(); break; } case CameraBrand.MicroCamera: { camera = new MicroCamera(); 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 地址和端口 // 更新正则以支持可选的数据类型字段 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; string DataType = match.Groups["DataType"].Success ? match.Groups["DataType"].Value : "String"; 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.CommunicatorConnections.Add("数据类型", DataType); 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(); string DataType = item.Value.CommunicatorConnections.Contains("数据类型") ? item.Value.CommunicatorConnections["数据类型"].ToString() : "String"; if (string.IsNullOrEmpty(ClassName) || string.IsNullOrEmpty(IP) || string.IsNullOrEmpty(PORT) || string.IsNullOrEmpty(CpuType) || string.IsNullOrEmpty(PlcAddress)) { break; } string CommunicatorConnectionString = $"({ClassName})[{IP}][{PORT}][{CpuType}][{PlcAddress}][{DataType}]"; 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); } GlobalVar.dicCommunicators[item.Key].ClassName = ClassName; } 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); foreach (var item in GlobalVar.dicCommunicators) { string ClassName = item.Value.GetType().FullName;// "TCP" } ConfigManager>.SaveConfig>(GlobalVar.dicCommunicators, GlobalVar.strApplicationPath + "\\所有产品\\" + GlobalVar.strProductName + "\\dicCommunicators.json"); 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(); //} } void SelectMainPage() { if (this.InvokeRequired) { this.Invoke(new Action(() => { if (materialTabControl.SelectedIndex == 0) { return; } materialTabControl.SelectedIndex = 0; ckbAllowRun.Enabled = false; materialTabControl.Enabled = false; materialTabSelector.Enabled = false; cmbProduct.Enabled = false; })); } else { if (materialTabControl.SelectedIndex == 0) { return; } materialTabControl.SelectedIndex = 0; ckbAllowRun.Enabled = false; materialTabControl.Enabled = false; materialTabSelector.Enabled = false; cmbProduct.Enabled = false; } } void UnSelectMainPage() { if (this.InvokeRequired) { this.Invoke(new Action(() => { ckbAllowRun.Enabled = true; materialTabControl.Enabled = true; materialTabSelector.Enabled = true; cmbProduct.Enabled = true; })); } else { ckbAllowRun.Enabled = true; materialTabControl.Enabled = true; materialTabSelector.Enabled = true; cmbProduct.Enabled = true; } } private void CommunicationProtocol(string msg, out ProtocolType ProtocolType, out string[] protocol, char splitChar = ';') { protocol = msg.Split(splitChar); if (msg.StartsWith("PCS")) { if (protocol.Length >= 1) { ProtocolType = ProtocolType.ProductChange; } else { ProtocolType = ProtocolType.Error; } } else if (msg.StartsWith("GVS")) { ProtocolType = ProtocolType.GetVersion; } else if (msg.StartsWith("NCS")) { if (protocol.Length >= 5) { ProtocolType = ProtocolType.NpointCaltab; } else { ProtocolType = ProtocolType.Error; } } else if (msg.StartsWith("CCS")) { if (protocol.Length >= 5) { ProtocolType = ProtocolType.CenterCaltab; } else { ProtocolType = ProtocolType.Error; } } else { ProtocolType = ProtocolType.Normal; } } private void TriggerRunMessageReceived(string name, string msg) { if (msg == null || msg.Trim('\0', '\r', '\n', ' ', '\uFEFF') == "" || string.IsNullOrEmpty(msg)) { return; } if (GlobalVar.strUserName.ToUpper() != "ADMIN") { SelectMainPage(); } LogInfo(string.Format("通讯[{0}]接收到的消息\"{1}\"", name, msg), LogInfoType.INFO); CommunicationProtocol(msg, out ProtocolType type, out string[] protocol); switch (type) { case ProtocolType.ProductChange: { string ProductName = protocol[1]; BaseCommunicator SendCom = GlobalVar.dicCommunicators[name]; if (!cmbProduct.Items.Contains(ProductName) || cmbProduct.FindString(ProductName) < 0) { LogInfo(string.Format($"通讯[{name}]触发切换产品{ProductName}不存在!"), LogInfoType.ERROR); GlobalVar.dicCommunicators[name].SendMessage($"PCE;0;"); LogInfo(string.Format("发送给[{0}]了消息\"{1}\"", name, "PCE;0;"), LogInfoType.INFO); return; } if (cmbProduct.FindString(ProductName) >= 0) { if (this.InvokeRequired) { this.Invoke(new Action(() => { if (cmbProduct.Text != ProductName) cmbProduct.SelectedIndex = cmbProduct.FindString(ProductName); })); } else if (cmbProduct.Text != ProductName) { cmbProduct.SelectedIndex = cmbProduct.FindString(ProductName); } LogInfo(string.Format($"通讯[{name}]触发切换产品{ProductName}成功!"), LogInfoType.INFO); GlobalVar.dicCommunicators[name].SendMessage($"PCE;1;"); LogInfo(string.Format("发送给[{0}]了消息\"{1}\"", name, "PCE;1;"), LogInfoType.INFO); } return; } case ProtocolType.GetVersion: { LogInfo(string.Format($"通讯[{name}]触发获取版本!"), LogInfoType.INFO); GlobalVar.dicCommunicators[name].SendMessage($"PCE;1;"); break; } case ProtocolType.NpointCaltab: { LogInfo(string.Format($"通讯[{name}]触发多点标定,暂不支持!"), LogInfoType.ERROR); return; } case ProtocolType.CenterCaltab: { LogInfo(string.Format($"通讯[{name}]触发中心标定,暂不支持!"), LogInfoType.ERROR); return; } case ProtocolType.Error: { LogInfo(string.Format($"通讯[{name}]指令非法,请查询通讯交互表!"), LogInfoType.ERROR); return; } } 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 (!ckbAllowRun.Checked) { LogInfo(string.Format($"检查到可被触发的流程,当前不为运行模式!"), LogInfoType.ERROR); return; } GlobalVar.dicProcesses.Values.AsParallel().ForAll(v => v.bCompleted = false); LogInfo(string.Format($"检查到可被触发的流程,清空所有流程运行完成标记位!"), LogInfoType.INFO); Task.Factory.StartNew(() => { 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 = RunBll.Run(); msg = RunBll.Msg; if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联")) { if (!result) { LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW); } RunBll.GetBooleanOutput(ConnecResult, out result); RunBll.Result = result; } if (!result) { LogInfo($"流程[{ProcessName}]被强制运行成功", LogInfoType.WARN); RunBll.Result = true; result = true; } } else { while (times >= 0) { result = RunBll.Run(); msg = RunBll.Msg; if (!(string.IsNullOrEmpty(ConnecResult) || ConnecResult.Trim() == "未关联")) { if (!result) { LogInfo(string.Format("流程[{0}]运行结果失败,原因是[{1}]", ProcessName, msg), LogInfoType.NOSHOW); } 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 (!AllProcessesPage.dicProcessControls.ContainsKey(title)) { continue; } RunBll.GetImage(layout, out InputImage, out RecordImage); AllProcessesPage.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; //try //{ // Process[] processes = System.Diagnostics.Process.GetProcesses(); //获得所有进程 // foreach (Process p in processes) // { // if (p.ProcessName == "LB_SmartVision" && p.StartTime < DateTime.Now.AddMilliseconds(-300)) // { // p.Kill(); // } // } //} //catch { } KillAllTargetProcesses(); } /// /// 杀进程逻辑 /// private void KillAllTargetProcesses() { try { // 1. 获取当前进程ID,避免杀死自己 int currentProcessId = Process.GetCurrentProcess().Id; // 2. 模糊匹配进程名(忽略大小写),覆盖vshost/后缀等情况 var targetProcesses = Process.GetProcesses() .Where(p => p.ProcessName.IndexOf("LB_SmartVision", StringComparison.OrdinalIgnoreCase) >= 0 && p.Id == currentProcessId); foreach (var p in targetProcesses) { try { if (!p.HasExited) { // 先尝试优雅关闭WinForm程序(比直接Kill更友好) p.CloseMainWindow(); // 等待500ms,看是否正常退出 if (!p.WaitForExit(500)) { p.Kill(); // 强制杀死 p.WaitForExit(1000); // 等待进程完全终止 } } p.Dispose(); // 释放进程资源,避免句柄泄漏 } catch (Exception ex) { // 记录异常但不中断,比如权限不足的情况 System.IO.File.AppendAllText("kill_process_log.txt", $"[{DateTime.Now}] 杀死进程失败: {ex.Message}\r\n"); } } // 额外延迟,确保文件句柄完全释放 Thread.Sleep(1000); } catch (Exception) { // 静默失败,不影响程序退出 } } private void btn_Run_Click(object sender, EventArgs e) { var matchedItems = GlobalVar.dicProcessSetting .Where(item => { var value = item.Value; var triggerComm = value["触发通讯"]; var triggerChar = value["触发字符"]; return triggerComm != null; //return triggerComm != null && triggerComm.Equals(name) && // (string.IsNullOrEmpty(triggerChar?.ToString()) || // msg.StartsWith(triggerChar.ToString())); }) .ToList(); // 避免重复字典访问和装箱操作 if (matchedItems.Count <= 0) { return; } TriggerRunMessageReceived(matchedItems[0].Value["触发通讯"], matchedItems[0].Value["触发字符"]); } private void btn_RunContinuously_Click(object sender, EventArgs e) { if (btn_RunContinuously.Text.Equals("连续运行")) { _isTabSwitchAllowed = false; btn_RunContinuously.Text = "暂停运行"; // 关闭使能 SelectMainPage(); btn_GlobalVar.Enabled = false; btn_Login.Enabled = false; btn_SingleRun.Enabled = false; ckbAllowRun.Enabled = false; Task.Factory.StartNew(() => { var matchedItems = GlobalVar.dicProcessSetting .Where(item => { var value = item.Value; var triggerComm = value["触发通讯"]; var triggerChar = value["触发字符"]; return triggerComm != null; //return triggerComm != null && triggerComm.Equals(name) && // (string.IsNullOrEmpty(triggerChar?.ToString()) || // msg.StartsWith(triggerChar.ToString())); }) .ToList(); // 避免重复字典访问和装箱操作 while (btn_RunContinuously.Text.Equals("暂停运行")) { TriggerRunMessageReceived(matchedItems[0].Value["触发通讯"], matchedItems[0].Value["触发字符"]); Thread.Sleep(3500); } //this.Invoke(() => //{ //}); }); } else if (btn_RunContinuously.Text.Equals("暂停运行")) { btn_RunContinuously.Text = "连续运行"; // 启动使能 UnSelectMainPage(); btn_GlobalVar.Enabled = true; btn_Login.Enabled = true; btn_SingleRun.Enabled = true; ckbAllowRun.Enabled = true; Thread.Sleep(100); _isTabSwitchAllowed = true; } } private void cmbProduct_SelectedValueChanged(object sender, EventArgs e) { if (cmbProduct.SelectedItem == null || cmbProduct.SelectedItem?.ToString() == GlobalVar.strProductName) { return; } if (cmbProduct.SelectedItem?.ToString() == "编辑") { using (CreateProductForm createDatabaseForm = new CreateProductForm()) { createDatabaseForm.ShowDialog(); } } else { //变更前保存现有配置 SaveAllSetting(); LogInfo($"产品从{GlobalVar.strProductName}切换{cmbProduct.SelectedItem?.ToString()}", LogInfoType.WARN); LB_SmartVision.Tool.Tool.WriteConfig("数据库名称", cmbProduct.SelectedItem?.ToString()); GlobalVar.strProductName = cmbProduct.SelectedItem?.ToString(); foreach (BaseCamera camera in GlobalVar.dicCameras.Values) { camera.TriggerRunMessageReceived -= TriggerRunMessageReceived; 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); NowBom = string.Empty; LB_SmartVision.Tool.Tool.WriteConfig("当前BOM", NowBom); } } private void rich_Info_MouseDoubleClick(object sender, MouseEventArgs e) { this.BeginInvoke(new Action(() => { this.rich_Info.Clear(); })); } private void cmbProduct_MouseDoubleClick(object sender, MouseEventArgs e) { this.BeginInvoke(new Action(() => { cmbProduct.Items.Clear(); LB_SmartVision.Tool.Tool.ReadStringConfig("产品列表", out string Products); List lstProduct = (Products.Split(',')).ToList(); foreach (string DatabaseName in lstProduct) { cmbProduct.Items.Add(DatabaseName); } cmbProduct.Items.Add("编辑"); cmbProduct.Text = GlobalVar.strProductName; })); } private void materialTabControl_SelectedIndexChanged(object sender, EventArgs e) { if (materialTabControl.SelectedTab == null || !_isTabSwitchAllowed) { return; } if (materialTabControl.SelectedIndex == 0) { this.btn_SingleRun.Enabled = true; this.btn_RunContinuously.Enabled = true; } else { this.btn_SingleRun.Enabled = false; this.btn_RunContinuously.Enabled = false; } // 切换 Tab 时强制重绘所有子控件 foreach (Control control in materialTabControl.SelectedTab.Controls) { control.Invalidate(); } materialCombobox1.SelectedItem = materialTabControl.SelectedTab.Text; } } }