參考文章《C# 線程更新UI界面》
主窗口
public frmMain() { InitializeComponent(); } /// <summary> /// 主窗口加載事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void frmMain_Load(object sender, EventArgs e) { try { //設置默認狀態 mc_MachineStatusHander = new Common.MachineStatusHandler(); mc_MachineStatusHander.mc_MachineProduceStatusHandler.UpdateMachineSignalDelegate += UpdateMachineSignalStatus;//后台線程中指定委托為更新界面方法 mc_MachineStatusHander.ChangeStatus("Online", "運行", "WesChen", "001A"); SettingLight(); } catch (Exception ex) { ShowErrorMessage(ex.Message, "系統初始化"); this.Close(); } }
界面更新主方法
/// <summary> /// 獲取機器信號,並更新界面 /// </summary> /// <param name="singnal">機器信號</param> delegate void UpdateMachineProduceSignalDelegate(Common.MachineProduceStatusHandler.SignalType singnal); private void UpdateMachineSignalStatus(Common.MachineProduceStatusHandler.SignalType signal) { if (InvokeRequired) { this.Invoke(new UpdateMachineProduceSignalDelegate(delegate (Common.MachineProduceStatusHandler.SignalType s) { if (signal.ToString().IndexOf("X01") != -1) { btn_SignalX01.BackColor= System.Drawing.Color.FromArgb(255, 255, 255); btn_SignalX01.ForeColor = System.Drawing.Color.FromArgb(0, 0, 0); } else { btn_SignalX01.BackColor = System.Drawing.Color.FromArgb(38, 45, 58); btn_SignalX01.ForeColor = System.Drawing.Color.FromArgb(255, 255, 255); } lab_ProductCount.Text = "累計生產數量:" + mc_MachineStatusHander.mc_MachineProduceStatusHandler.ProductCount; lab_LastLifeCycleTime.Text = "最后一次生產用時:" + Common.CommonFunction.FormatMilliseconds(mc_MachineStatusHander.mc_MachineProduceStatusHandler.LastProductUseMilliseconds); }), signal); } else { if (signal.ToString().IndexOf("X01") != -1) { btn_SignalX01.BackColor = System.Drawing.Color.FromArgb(255, 255, 255); btn_SignalX01.ForeColor = System.Drawing.Color.FromArgb(0, 0, 0); } else { btn_SignalX01.BackColor = System.Drawing.Color.FromArgb(38, 45, 58); btn_SignalX01.ForeColor = System.Drawing.Color.FromArgb(255, 255, 255); } lab_ProductCount.Text = "累計生產數量:" + mc_MachineStatusHander.mc_MachineProduceStatusHandler.ProductCount; lab_LastLifeCycleTime.Text = "最后一次生產用時:" + Common.CommonFunction.FormatMilliseconds(mc_MachineStatusHander.mc_MachineProduceStatusHandler.LastProductUseMilliseconds); } }
后台線程
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Text.RegularExpressions; using System.Diagnostics; namespace MES_MonitoringClient.Common { /// <summary> /// 機器生產狀態 /// </summary> public class MachineProduceStatusHandler { /// <summary> /// 信號類型 /// </summary> public enum SignalType { Unknow, X01, X02, X03, X01_X02, X01_X03, X02_X03, X01_X02_X03 } /// <summary> /// 回復信號前綴 /// </summary> private static string singnalDefaultStart = Common.ConfigFileHandler.GetAppConfig("GetSerialPortDataDefaultSignal_StartPrefix"); /// <summary> /// 回復信號后綴 /// </summary> private static string singnalDefaultEnd = Common.ConfigFileHandler.GetAppConfig("GetSerialPortDataDefaultSignal_EndPrefix"); /*-------------------------------------------------------------------------------------*/ /// <summary> /// 產品生命周期(計算時間) /// </summary> //private List<MachineProcedure> _MachineProcedureListForTime=null; /// <summary> /// 產品生命周期(計算次數) /// </summary> private List<MachineProcedure> _MachineProcedureListForCount=null; /// <summary> /// 產品周期計數(生產數量) /// </summary> public int ProductCount = 0; /// <summary> /// 空產品周期計數(不完整[空啤]生產數量) /// </summary> public int ProductErrorCount = 0; /// <summary> /// 單次產品周期秒數 /// </summary> public long LastProductUseMilliseconds = 0; /// <summary> /// /// </summary> public Nullable<DateTime> LastX03SignalGetTime = null; /// <summary> /// 上一個信號 /// </summary> public SignalType LastSignal; /// <summary> /// 更新機器信號后更新界面的方法與委托 /// </summary> /// <param name="signalType"></param> public delegate void UpdateMachineSignal(SignalType signalType); public UpdateMachineSignal UpdateMachineSignalDelegate; /*-------------------------------------------------------------------------------------*/ /// <summary> /// 構造函數,處理初始化的參數 /// </summary> public MachineProduceStatusHandler() { //產品生命周期(計算時間) //_MachineProcedureListForTime = new List<MachineProcedure>(); //產品生命周期(計算次數) _MachineProcedureListForCount = new List<MachineProcedure>(); } /*-------------------------------------------------------------------------------------*/ /// <summary> /// 更新信號方法 /// </summary> /// <param name="newSingnal">新信號</param> public void ChangeSignal(string newSingnal) { string convertSingnalString = ConvertSingnalString(newSingnal); //判斷是正常的信號 if (!string.IsNullOrEmpty(convertSingnalString)) { //判斷X信號 SignalType convertSingnalStatusType = ConvertSingnalStatus(convertSingnalString); if (convertSingnalStatusType != LastSignal) { #region 與上一次信號不同 if (convertSingnalStatusType == SignalType.X03) { #region 自動信號(區分上一個信號) _MachineProcedureListForCount.Add(new MachineProcedure() { ProcedureID = convertSingnalString, ProcedureCode = convertSingnalStatusType.ToString(), ProcedureName = "自動", }); if (LastSignal == SignalType.X01_X03) { //結束產品周期並計時 if (LastX03SignalGetTime.HasValue) { LastProductUseMilliseconds = (System.DateTime.Now - LastX03SignalGetTime.Value).Milliseconds; } LastX03SignalGetTime = System.DateTime.Now; } else if (LastSignal == SignalType.X02_X03) { //必須包含完整的生命周期才計數 if (CheckHaveRealProduceProcess(_MachineProcedureListForCount)) { //計數 ProductCount++; _MachineProcedureListForCount.Clear(); _MachineProcedureListForCount.Add(new MachineProcedure() { ProcedureID = convertSingnalString, ProcedureCode = convertSingnalStatusType.ToString(), ProcedureName = "自動", }); } } #endregion } else if (convertSingnalStatusType == SignalType.X01_X03 || convertSingnalStatusType == SignalType.X02_X03) { #region 開模完成==射膠完成(不區分上一個信號) //產品生命周期(計算數量) if (_MachineProcedureListForCount != null && _MachineProcedureListForCount.Count > 0) { //信號 string procedureNameString = string.Empty; if (convertSingnalStatusType == SignalType.X01_X03) procedureNameString = "開模完成"; else if (convertSingnalStatusType == SignalType.X02_X03) procedureNameString = "自動射膠"; _MachineProcedureListForCount.Add(new MachineProcedure() { ProcedureID = convertSingnalString, ProcedureCode = convertSingnalStatusType.ToString(), ProcedureName = procedureNameString, }); } #endregion } #endregion //上一個信號 LastSignal = convertSingnalStatusType; //根據信號更新界面 UpdateMachineSignalDelegate(LastSignal); } } } /// <summary> /// 匹配信號是否正常 /// 並返回信號中的模式數字 /// </summary> /// <param name="inputSingnal">原信號</param> /// <returns></returns> private string ConvertSingnalString(string inputSingnal) { Regex regex = new Regex("^" + singnalDefaultStart + "[a-fA-F0-9]{4}" + singnalDefaultEnd + "$"); Match match = regex.Match(inputSingnal); if (match.Success) { Regex regexMiddle = new Regex("(?<=(" + singnalDefaultStart + "))[.\\s\\S]*?(?=(" + singnalDefaultEnd + "))", RegexOptions.Multiline | RegexOptions.Singleline); Match matchMiddle = regexMiddle.Match(inputSingnal); return matchMiddle.Value; } else { return null; } } /// <summary> /// 模式數字轉換為X[]信號 /// </summary> /// <param name="inputSingnal">模式數字[0800,0400,0200,0C00,0A00,0600,0E00等模式數字]</param> /// <returns></returns> private SignalType ConvertSingnalStatus(string inputSingnal) { if (inputSingnal == "0800") return SignalType.X01; //開模終止信號 else if (inputSingnal == "0400") return SignalType.X02;//射膠信號 else if (inputSingnal == "0200") return SignalType.X03;//自動運行模式信號 else if (inputSingnal == "0C00") return SignalType.X01_X02; else if (inputSingnal == "0A00") return SignalType.X01_X03; else if (inputSingnal == "0600") return SignalType.X02_X03; else if (inputSingnal == "0E00") return SignalType.X01_X02_X03; else return SignalType.Unknow; } /// <summary> /// 判斷是否是真實的生產流程 /// </summary> /// <param name="oldMachineProcedureList"></param> /// <returns></returns> private bool CheckHaveRealProduceProcess(List<MachineProcedure> oldMachineProcedureList) { bool resultFlag = false; bool isX01_X03 = false; bool isX02_X03 = false; bool isX03 = false; //判斷是否有完整的信號 foreach (var processItem in oldMachineProcedureList) { if (processItem.ProcedureCode == SignalType.X01_X03.ToString()) isX01_X03 = true; if (processItem.ProcedureCode == SignalType.X02_X03.ToString()) isX02_X03 = true; if (processItem.ProcedureCode == SignalType.X03.ToString()) isX03 = true; } //完整的信號則算正常生產流程 if (isX01_X03 && isX02_X03 && isX03) resultFlag = true; return resultFlag; } } }
以上方法是可以正常從類內部更新winform界面的