using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Bro.Common.Interface; namespace Bro.Common.Base.UI { public partial class CtrlPLCRunBase : UserControl, IRunCtrl { public CtrlPLCRunBase() { InitializeComponent(); } public IDevice Device { get; set; } protected PLCBase PLC { get => Device as PLCBase; } System.Threading.Timer _monitorLineChangedTimer = null; System.Threading.Timer _refreshFrequenceChangedTimer = null; System.Threading.Timer _refreshMonitorTimer = null; public CtrlPLCRunBase(IDevice device) { InitializeComponent(); Device = device; dgvMonitor.AutoGenerateColumns = false; dgvMonitor.ReadOnly = true; dgvMonitor.AllowUserToAddRows = false; dgvMonitor.AllowUserToDeleteRows = false; SetMonitorGrid(); _monitorLineChangedTimer = new System.Threading.Timer(OnMonitorLineChanged, null, -1, -1); _refreshFrequenceChangedTimer = new System.Threading.Timer(OnRefreshFrequenceChanged, null, -1, -1); _refreshMonitorTimer = new System.Threading.Timer(OnRefreshMonitorValues, null, 0, 1000); cboFormat.SelectedIndex = 0; cboFormat.SelectedIndexChanged += CboFormat_SelectedIndexChanged; } string _displayFormat = "G"; private void CboFormat_SelectedIndexChanged(object sender, EventArgs e) { switch (cboFormat.SelectedIndex) { case 0: _displayFormat = "G"; break; case 1: _displayFormat = "X2"; break; case 2: _displayFormat = ""; break; default: break; } oldValues = null; } private void OnMonitorLineChanged(object state) { txtMonitorLines.Invoke(new Action(() => { string temp = txtMonitorLines.Text.Trim(); if (!int.TryParse(temp, out int lines)) { txtMonitorLines.Text = "10"; lines = 10; } MonitorLines = lines; })); } int MonitorLines { get { string temp = txtMonitorLines.Text.Trim(); if (!int.TryParse(temp, out int lines)) { txtMonitorLines.Text = "10"; lines = 10; } return lines; } set { SetMonitorGrid(); } } private void txtMonitorLines_TextChanged(object sender, EventArgs e) { _monitorLineChangedTimer.Change(1000, -1); } private void SetMonitorGrid() { int rowLines = MonitorLines; dgvMonitor.Rows.Clear(); dgvMonitor.Columns.Clear(); for (int i = 0; i < PLC.PLCIConfig.EventLength; i++) { int rowNum = i % rowLines; int colNum = i / rowLines; if (dgvMonitor.Columns.Count <= colNum * 2) { var colAddr = new DataGridViewColumn(new DataGridViewTextBoxCell()); colAddr.HeaderText = "监听地址"; dgvMonitor.Columns.Add(colAddr); var colValue = new DataGridViewColumn(new DataGridViewTextBoxCell()); colValue.HeaderText = "监听数值"; dgvMonitor.Columns.Add(colValue); } if (dgvMonitor.Rows.Count <= rowNum) { dgvMonitor.Rows.Add(new DataGridViewRow()); } dgvMonitor.Rows[rowNum].Cells[colNum * 2].Value = (PLC.PLCIConfig.EventStartAddress + i).ToString(); dgvMonitor.Rows[rowNum].Cells[colNum * 2 + 1].Value = ""; } } int RefreshFrequence { get { string temp = txtRefreshFrequence.Text.Trim(); if (!int.TryParse(temp, out int freq)) { txtRefreshFrequence.Text = "1000"; freq = 1000; } return freq; } set { SetRefreshFrequence(); } } private void SetRefreshFrequence() { _refreshMonitorTimer.Change(RefreshFrequence, RefreshFrequence); } private void txtRefreshFrequence_TextChanged(object sender, EventArgs e) { _refreshFrequenceChangedTimer.Change(1000, -1); } private void OnRefreshFrequenceChanged(object state) { txtRefreshFrequence.Invoke(new Action(() => { string temp = txtRefreshFrequence.Text.Trim(); if (!int.TryParse(temp, out int freq)) { txtRefreshFrequence.Text = "1000"; freq = 1000; } RefreshFrequence = freq; })); } List oldValues = null; Dictionary _cellChangedTimerDict = new Dictionary(); private void OnRefreshMonitorValues(object state) { if (PLC.CurrentState != Helper.EnumHelper.DeviceState.DSOpen) return; List newValues = new List(PLC.MonitorValues); if (oldValues == null || oldValues.Count != newValues.Count) { for (int i = 0; i < newValues.Count; i++) { int rowNum = i % MonitorLines; int colNum = i / MonitorLines; //string displayStr = ""; //if (_displayFormat != "") //{ // displayStr = newValues[i].ToString(_displayFormat); //} //else //{ // displayStr = ConvertToBinaryString(newValues[i]); //} dgvMonitor.Rows[rowNum].Cells[colNum * 2 + 1].Value = GetSignedShortValue(newValues[i]); } } else { for (int i = 0; i < oldValues.Count; i++) { if (oldValues[i] != newValues[i]) { int rowNum = i % MonitorLines; int colNum = i / MonitorLines; var cell = dgvMonitor.Rows[rowNum].Cells[colNum * 2 + 1]; //string displayStr = ""; //if (_displayFormat != "") //{ // displayStr = newValues[i].ToString(_displayFormat); //} //else //{ // displayStr = ConvertToBinaryString(newValues[i]); //} //cell.Value = displayStr; cell.Value = GetSignedShortValue(newValues[i]); cell.Style.BackColor = Color.PaleGreen; cell.Style.ForeColor = Color.Red; if (!_cellChangedTimerDict.ContainsKey(i)) { _cellChangedTimerDict[i] = new System.Threading.Timer(OnChangedDisplayTimeout, new object[] { cell, i }, 1000, -1); } else { _cellChangedTimerDict[i].Change(1000, -1); } } } } oldValues = new List(newValues); } private string GetSignedShortValue(int v) { string displayStr = ""; switch (_displayFormat) { case "G": displayStr = ((short)v).ToString(_displayFormat); break; case "X2": displayStr = "0x" + ((short)v).ToString(_displayFormat); break; case "": displayStr = ConvertToBinaryString((short)v); break; default: break; } return displayStr; } private string ConvertToBinaryString(short origin) { string binStr = ""; //int length = v / 2; //if (v % 2 > 0) //{ // length++; //} //if (length == 0) // length++; //for (int i = 0; i < length; i++) //{ // binStr += (v >> i & 1).ToString(); //} //int origin = v; if (origin == 0) return "00000000"; bool isNegative = false; if (origin < 0) { origin = (short)(0 - origin); isNegative = true; } do { int addtional = origin % 2; binStr = (addtional.ToString() + binStr); origin = (short)(origin / (short)2); } while (origin != 1); binStr = ("1" + binStr).PadLeft(8, '0'); if (isNegative) { var list = binStr.ToList().ConvertAll(s => s == '1' ? "0" : "1"); int last0Index = list.LastIndexOf("0"); for (int i = last0Index; i < list.Count; i++) { list[i] = list[i] == "0" ? "1" : "0"; } binStr = string.Join("", list); } return binStr; } private void OnChangedDisplayTimeout(object state) { DataGridViewCell cell = (DataGridViewCell)((state as object[])[0]); int index = (int)((state as object[])[1]); cell.Style.BackColor = SystemColors.Control; cell.Style.ForeColor = SystemColors.ControlText; _cellChangedTimerDict.Remove(index); } } }