using PlcCom; using PlcComponent; using Sunny.UI.Win32; using System; using System.CodeDom; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Timer = System.Windows.Forms.Timer; public class PlcBindingManager { private readonly List singleOutputComponents =new List(); private readonly List singleInputComponents = new List(); private readonly List multiOutputComponents = new List(); private readonly List multiInputComponents = new List(); private List controlsWithInvisibilityProperty = new List(); private List controlsWithDisabilityProperty = new List(); private readonly List readAddressesOfSingleOutputComs = new List(); private readonly List writeAddressesOfSingleInputComs = new List(); private TimeSpan TimeSpanReadOverTime = TimeSpan.FromSeconds(1); private List timers=new List(); private Dictionary> dictInvisibilityTriggerNode_Controls; private Dictionary> dictDisabilityTriggerNode_Controls; public void Bind(List components,List controls) { foreach (var c in components) { if (c is ISingleOutputComponent soc) { if (soc.ReadNode != null && !string.IsNullOrEmpty(soc.ReadNode.Value)) { singleOutputComponents.Add(soc); //readAddressesOfSingleOutputComs.Add(soc.ReadNode.Value); } } if (c is ISingleInputComponent sic) { if (sic.WriteNode != null && !string.IsNullOrEmpty(sic.WriteNode.Value)) { singleInputComponents.Add(sic); writeAddressesOfSingleInputComs.Add(sic.WriteNode.Value); } } if (c is IMultiOutputComponent moc) { if (moc.ReadNodes != null) multiOutputComponents.Add(moc); } if (c is IPlcMultiInputComponent mic) { if (mic.WriteNodes != null) multiInputComponents.Add(mic); } } foreach (var item in controls) { if (item.InvisibilityTriggerNode != null) controlsWithInvisibilityProperty.Add(item); if (item.DisabilityTriggerNode != null) controlsWithDisabilityProperty.Add(item); } dictInvisibilityTriggerNode_Controls = controlsWithInvisibilityProperty .GroupBy(c => c.InvisibilityTriggerNode.Value) .ToDictionary(g => g.Key, g => g.ToList()); dictDisabilityTriggerNode_Controls = controlsWithDisabilityProperty .GroupBy(c => c.DisabilityTriggerNode.Value) .ToDictionary(g => g.Key, g => g.ToList()); } public void SetPlcContext(PlcContex context, int intervalMs = 100) { SetBingControlsProtocol(context.Protocol); if (context.Protocol.IsConnected) { /*********************************剔除绑定单个地址的无效组件地址,并开始刷新组件*********************************************/ RemoveInvalidNodes(context, singleOutputComponents);//单个刷新一次,把无法读取的控件剔除掉 readAddressesOfSingleOutputComs.AddRange(singleOutputComponents.Select(c=>c.ReadNode.Value).ToList()); /**********************************剔除无效的控件不可见触发地址,并开始刷新组件********************************************/ RemoveInvalidNodes(context, dictInvisibilityTriggerNode_Controls);//单个刷新一次,把无法读取的控件剔除掉 /**********************************剔除无效的控件不可用触发地址,并开始刷新组件********************************************/ RemoveInvalidNodes(context, dictDisabilityTriggerNode_Controls);//单个刷新一次,把无法读取的控件剔除掉 if (singleOutputComponents.Count > 0 || dictInvisibilityTriggerNode_Controls.Count > 0 || dictDisabilityTriggerNode_Controls.Count > 0) { Timer _timer; _timer = new Timer(); _timer.Interval = intervalMs; _timer.Tick += async (s, e) =>{ ((Timer)s).Stop(); if(singleOutputComponents.Count > 0) await RefreshSingleOutputComponentsByListAsync(context); if (dictInvisibilityTriggerNode_Controls.Count > 0) await RefreshInvisibilityTriggerNodeAsync(context, dictInvisibilityTriggerNode_Controls); if (dictDisabilityTriggerNode_Controls.Count > 0) await RefreshDisabilityTriggerNodeAsync(context, dictDisabilityTriggerNode_Controls); ((Timer)s).Start(); };// RemoveInvalidNodes(context); _timer.Start(); timers.Add(_timer); } /**********************************剔除绑定多个地址的无效组件地址,并开始刷新组件********************************************/ foreach (var c in multiOutputComponents) { if (c.BackgroundRefreshEnable) { var invalidNodes= c.RemoveInvalidNodes(); foreach (var node in invalidNodes) { ReadOneNodeFailed.Invoke(c, node, 0); } if (c.ReadNodes.Count > 0) { var timer = new Timer(); timer.Interval = c.ReadInterval; timer.Tick += async (s, e) => { ((Timer)s).Stop(); await RefreshMultiOutputComponentsByListAsync(context, c); ((Timer)s).Start(); }; timer.Start(); timers.Add(timer); } } } } } void SetBingControlsProtocol(IPlcComProtocol plcComProtocol) { foreach (var component in singleOutputComponents) { component.Protocol = plcComProtocol; } foreach (var component in singleInputComponents) { component.Protocol = plcComProtocol; } foreach (var component in multiOutputComponents) { component.Protocol = plcComProtocol; } foreach (var component in multiInputComponents) { component.Protocol = plcComProtocol; } } public event Action ReadOK; public event Action ReadOneNodeFailed; public event Action, uint> ReadMultiNodesFailed; public event Action ReadOverTime; /// /// 逐个读取单个输出的控件,目的是剔除掉无法读取的控件 /// /// private List RemoveInvalidNodes(PlcContex context, List components) { var toRemove = new List(); List strings = components.Select(n => n.ReadNode.Value).ToList(); try { var rt= context.Protocol.ReadValue(strings, out List results); if(rt==0) { for(int i = 0; i < strings.Count; i++) { if (results[i]==null) { toRemove.Add(components[i]); } } } } catch (Exception) { } foreach (var item in toRemove) { components.Remove(item); ReadOneNodeFailed.Invoke(item, item.ReadNode, 0); } return components; } private Dictionary> RemoveInvalidNodes(PlcContex context, Dictionary> keyValuePairs) { var toRemove = new List<(string,List)>(); List strings = keyValuePairs.Select(k => k.Key).ToList(); try { var rt = context.Protocol.ReadValue(strings, out List results); if (rt == 0) { for (int i = 0; i < strings.Count; i++) { if (results[i] == null) { toRemove.Add((strings[i],keyValuePairs[strings[i]])); keyValuePairs.Remove(strings[i]); } } } } catch (Exception) { } foreach (var item in toRemove) { foreach (var c in item.Item2) { ReadOneNodeFailed.Invoke((IPlcBindableComponent)c, new Node(item.Item1), 0); } } return keyValuePairs; } private int _isReading = 0; // 0 = idle, 1 = busy /// /// 批量读取页面中单个输出的控件 /// /// private async Task RefreshSingleOutputComponentsByListAsync(PlcContex context) { if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 0) { try { List results; Stopwatch stopwatch = Stopwatch.StartNew(); var task = Task.Run(() => { var readRt = context.Protocol.ReadValue(readAddressesOfSingleOutputComs, out results); return (readRt, results); }); // 使用超时等待 if (await Task.WhenAny(task, Task.Delay(TimeSpanReadOverTime)) == task) { // 在超时前完成 var rt = await task; if (rt.readRt == 0) { ReadOK?.Invoke(); for (int i = 0; i < rt.results.Count; i++) { singleOutputComponents[i].UpdateValue(rt.results[i]); } } else { ReadMultiNodesFailed?.Invoke(readAddressesOfSingleOutputComs, rt.readRt); } } else { ReadOverTime?.Invoke(); } } finally { _isReading = 0; // 重置 } } } private async Task RefreshMultiOutputComponentsByListAsync(PlcContex context, IMultiOutputComponent c) { if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 0) { try { Stopwatch stopwatch = Stopwatch.StartNew(); List strings = c.ReadNodes.Select(n => n.Value).ToList(); var task = Task.Run(() => { var readRt = context.Protocol.ReadValue(strings, out List results); return (readRt, results); }); // 使用超时等待 if (await Task.WhenAny(task, Task.Delay(TimeSpanReadOverTime)) == task) { // 在超时前完成 var rt = await task; if (rt.readRt == 0) { ReadOK?.Invoke(); c.UpdateValues(c.ReadNodes, rt.results); } else { ReadMultiNodesFailed?.Invoke(strings, rt.readRt); } } else { ReadOverTime?.Invoke(); } } finally { _isReading = 0; // 重置 } } } private List invisibilityTriggerNode; private bool _isCacheValid = false; private void EnsureInvisibilityTriggerNodes(Dictionary> dictNodeControls) { if (!_isCacheValid) { invisibilityTriggerNode = dictNodeControls.ToList().Select(kv => kv.Key).ToList(); _isCacheValid = true; } } private async Task RefreshInvisibilityTriggerNodeAsync(PlcContex context, Dictionary> dictNodeControls) { if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 0) { try { EnsureInvisibilityTriggerNodes(dictNodeControls); List results; Stopwatch stopwatch = Stopwatch.StartNew(); var task = Task.Run(() => { var readRt = context.Protocol.ReadValue(invisibilityTriggerNode, out results); return (readRt, results); }); // 使用超时等待 if (await Task.WhenAny(task, Task.Delay(TimeSpanReadOverTime)) == task) { // 在超时前完成 var rt = await task; if (rt.readRt == 0) { for (int i = 0; i < invisibilityTriggerNode.Count; i++) { if (rt.results[i] is bool b) { foreach (var control in dictNodeControls[invisibilityTriggerNode[i]]) { control.Invisibility = control.ValueForInvisibility == b; } } } } else { ReadMultiNodesFailed?.Invoke(invisibilityTriggerNode, rt.readRt); } } } finally { _isReading = 0; // 重置 } } } private List disabilityTriggerNode; private bool _isCacheValid2 = false; private void EnsureDisabilityTriggerNodes(Dictionary> dictNodeControls) { if (!_isCacheValid2) { disabilityTriggerNode = dictNodeControls.ToList().Select(kv => kv.Key).ToList(); _isCacheValid2 = true; } } private async Task RefreshDisabilityTriggerNodeAsync(PlcContex context, Dictionary> dictNodeControls) { if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 0) { try { EnsureDisabilityTriggerNodes(dictNodeControls); List results; Stopwatch stopwatch = Stopwatch.StartNew(); var task = Task.Run(() => { var readRt = context.Protocol.ReadValue(disabilityTriggerNode, out results); return (readRt, results); }); // 使用超时等待 if (await Task.WhenAny(task, Task.Delay(TimeSpanReadOverTime)) == task) { // 在超时前完成 var rt = await task; if (rt.readRt == 0) { for (int i = 0; i < disabilityTriggerNode.Count; i++) { if (rt.results[i] is bool b) { foreach (var control in dictNodeControls[disabilityTriggerNode[i]]) { control.Disability = control.ValueForDisability && b; } } } } else { ReadMultiNodesFailed?.Invoke(disabilityTriggerNode, rt.readRt); } } } finally { _isReading = 0; // 重置 } } } public void Stop() { foreach (var item in timers) { item.Stop(); } } }