| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- 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<ISingleOutputComponent> singleOutputComponents =new List<ISingleOutputComponent>();
- private readonly List<ISingleInputComponent> singleInputComponents = new List<ISingleInputComponent>();
- private readonly List<IMultiOutputComponent> multiOutputComponents = new List<IMultiOutputComponent>();
- private readonly List<IPlcMultiInputComponent> multiInputComponents = new List<IPlcMultiInputComponent>();
- private List<IPlcUiControl> controlsWithInvisibilityProperty = new List<IPlcUiControl>();
- private List<IPlcUiControl> controlsWithDisabilityProperty = new List<IPlcUiControl>();
- private readonly List<string> readAddressesOfSingleOutputComs = new List<string>();
- private readonly List<string> writeAddressesOfSingleInputComs = new List<string>();
- private TimeSpan TimeSpanReadOverTime = TimeSpan.FromSeconds(1);
- private List<Timer> timers=new List<Timer>();
- private Dictionary<string, List<IPlcUiControl>> dictInvisibilityTriggerNode_Controls;
- private Dictionary<string, List<IPlcUiControl>> dictDisabilityTriggerNode_Controls;
- public void Bind(List<IPlcBindableComponent> components,List<IPlcUiControl> 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<IPlcBindableComponent,Node,uint> ReadOneNodeFailed;
- public event Action<List<string>, uint> ReadMultiNodesFailed;
- public event Action ReadOverTime;
-
- /// <summary>
- /// 逐个读取单个输出的控件,目的是剔除掉无法读取的控件
- /// </summary>
- /// <param name="context"></param>
- private List<ISingleOutputComponent> RemoveInvalidNodes(PlcContex context, List<ISingleOutputComponent> components)
- {
- var toRemove = new List<ISingleOutputComponent>();
- List<string> strings = components.Select(n => n.ReadNode.Value).ToList();
- try
- {
- var rt= context.Protocol.ReadValue(strings, out List<object> 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<string, List<IPlcUiControl>> RemoveInvalidNodes(PlcContex context, Dictionary<string, List<IPlcUiControl>> keyValuePairs)
- {
- var toRemove = new List<(string,List<IPlcUiControl>)>();
- List<string> strings = keyValuePairs.Select(k => k.Key).ToList();
- try
- {
- var rt = context.Protocol.ReadValue(strings, out List<object> 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
- /// <summary>
- /// 批量读取页面中单个输出的控件
- /// </summary>
- /// <param name="context"></param>
- private async Task RefreshSingleOutputComponentsByListAsync(PlcContex context)
- {
- if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 0)
- {
- try
- {
- List<object> 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<string> strings = c.ReadNodes.Select(n => n.Value).ToList();
- var task = Task.Run(() =>
- {
- var readRt = context.Protocol.ReadValue(strings, out List<object> 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<string> invisibilityTriggerNode;
- private bool _isCacheValid = false;
- private void EnsureInvisibilityTriggerNodes(Dictionary<string, List<IPlcUiControl>> dictNodeControls)
- {
- if (!_isCacheValid)
- {
- invisibilityTriggerNode = dictNodeControls.ToList().Select(kv => kv.Key).ToList();
- _isCacheValid = true;
- }
- }
- private async Task RefreshInvisibilityTriggerNodeAsync(PlcContex context, Dictionary<string, List<IPlcUiControl>> dictNodeControls)
- {
- if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 0)
- {
- try
- {
- EnsureInvisibilityTriggerNodes(dictNodeControls);
- List<object> 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<string> disabilityTriggerNode;
- private bool _isCacheValid2 = false;
- private void EnsureDisabilityTriggerNodes(Dictionary<string, List<IPlcUiControl>> dictNodeControls)
- {
- if (!_isCacheValid2)
- {
- disabilityTriggerNode = dictNodeControls.ToList().Select(kv => kv.Key).ToList();
- _isCacheValid2 = true;
- }
- }
- private async Task RefreshDisabilityTriggerNodeAsync(PlcContex context, Dictionary<string, List<IPlcUiControl>> dictNodeControls)
- {
- if (Interlocked.CompareExchange(ref _isReading, 1, 0) == 0)
- {
- try
- {
- EnsureDisabilityTriggerNodes(dictNodeControls);
- List<object> 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();
- }
- }
- }
|