RealTimeViewModel.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Drawing;
  5. using System.Linq;
  6. using System.Windows;
  7. using Aitex.Core.RT.Log;
  8. using Aitex.Core.Util;
  9. using Aitex.Core.Utilities;
  10. using MECF.Framework.Common.ControlDataContext;
  11. using MECF.Framework.Common.DataCenter;
  12. using MECF.Framework.Common.Utilities;
  13. using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory;
  14. using MECF.Framework.UI.Client.ClientBase;
  15. using MECF.Framework.UI.Client.ClientBase.Charting;
  16. using MECF.Framework.UI.Client.ClientBase.EventArgs;
  17. using MECF.Framework.UI.Client.ClientBase.Tree;
  18. using OpenSEMI.ClientBase;
  19. using SciChart.Charting.Visuals.Axes;
  20. using SciChart.Charting.Visuals.RenderableSeries;
  21. using SciChart.Core.Extensions;
  22. namespace MECF.Framework.UI.Client.CenterViews.Operations.RealTime
  23. {
  24. public class RealtimeViewModel : BusyIndicateableUiViewModelBase
  25. {
  26. #region Variables
  27. /// <summary>
  28. /// 允许监控的最大曲线数量
  29. /// </summary>
  30. private const int MAX_PARAMETERS_ALLOWED = 200;
  31. private readonly RealtimeProvider _provider = new RealtimeProvider();
  32. private bool _enableAutoZoom = true;
  33. private int _pointCount;
  34. private readonly PeriodicJob _thread;
  35. /// <summary>
  36. /// Monitor中添加数据点时直接向DataSeries对象添加,已实现跨线程操作。
  37. /// </summary>
  38. private readonly List<FastLineDataSeries> _dataSeriesList;
  39. /// <summary>
  40. /// 更新报告导出信息。
  41. /// </summary>
  42. private readonly IProgress<ProgressUpdatingEventArgs> _exportingProgressReporter;
  43. #endregion
  44. #region Constructors
  45. private static Dictionary<string, string> _displayDic { get; set; } = new Dictionary<string, string>();
  46. public RealtimeViewModel()
  47. {
  48. DisplayName = "Realtime";
  49. SelectedData = new ChartingLineSeriesCollection(DisplayName);
  50. ParameterNodes = new TreeNode(DisplayName)
  51. {
  52. MaxTerminalSelectionAllowed = MAX_PARAMETERS_ALLOWED
  53. };
  54. ParameterNodes.ChildNodes.AddRange(_provider.GetTreeNodeParameters());
  55. ParameterNodes.TerminalNodeSelectionChanged += OnNodeSelectionChanged;
  56. _displayDic = _provider.GetTreeNameDict();
  57. IntervalSaved = true;
  58. TrendInterval = 500;
  59. TimeSpanSaved = true;
  60. TrendTimeSpan = 60 * 5;
  61. _thread = new PeriodicJob(TrendInterval, MonitorData, "RealTime", true);
  62. _pointCount = Math.Max(TrendTimeSpan * 1000 / TrendInterval, 10);
  63. _dataSeriesList = new List<FastLineDataSeries>();
  64. _exportingProgressReporter = new Progress<ProgressUpdatingEventArgs>(e =>
  65. {
  66. BusyIndicatorContent = e.Message;
  67. });
  68. }
  69. #endregion
  70. #region Properties
  71. public bool IsPermission => this.Permission >1;
  72. public TreeNode ParameterNodes { get; }
  73. public ChartingLineSeriesCollection SelectedData { get; set; }
  74. public AutoRange ChartAutoRange => EnableAutoZoom ? AutoRange.Always : AutoRange.Never;
  75. public bool EnableAutoZoom
  76. {
  77. get => _enableAutoZoom;
  78. set
  79. {
  80. _enableAutoZoom = value;
  81. NotifyOfPropertyChange(nameof(EnableAutoZoom));
  82. NotifyOfPropertyChange(nameof(ChartAutoRange));
  83. }
  84. }
  85. [IgnorePropertyChange]
  86. public int TrendInterval { get; set; }
  87. public bool IntervalSaved { get; set; }
  88. [IgnorePropertyChange]
  89. public int TrendTimeSpan { get; set; }
  90. public bool TimeSpanSaved { get; set; }
  91. #endregion
  92. #region Methods
  93. protected bool MonitorData()
  94. {
  95. try
  96. {
  97. Dictionary<string, object> data = new Dictionary<string, object>();
  98. if (SelectedData.Count > 0)
  99. {
  100. var rtData = QueryDataClient.Instance.Service.PollData(SelectedData.Select(r => FindKeyByValue(_displayDic, (r as FastLineSeries)?.DataName)).ToList());
  101. foreach (var item in rtData)
  102. {
  103. var uiName = _displayDic[item.Key];
  104. data.Add(uiName, item.Value);
  105. }
  106. AppendData(data);
  107. }
  108. for (var j = 0; j < ParameterNodes.ChildNodes.Count; j++)
  109. {
  110. var par = ParameterNodes.ChildNodes[j];
  111. par.IsVisibilityParentNode = Visibility.Hidden;
  112. }
  113. }
  114. catch (Exception ex)
  115. {
  116. LOG.Error(ex.Message);
  117. }
  118. return true;
  119. }
  120. static string FindKeyByValue(Dictionary<string, string> dictionary, string value)
  121. {
  122. foreach (var pair in dictionary)
  123. {
  124. if (pair.Value == value)
  125. {
  126. return pair.Key;
  127. }
  128. }
  129. return null; // Return null if the value is not found
  130. }
  131. public void AppendData(Dictionary<string, object> data)
  132. {
  133. if (data == null)
  134. return;
  135. var dt = DateTime.Now;
  136. foreach (var ds in _dataSeriesList)
  137. {
  138. if (ds == null || !data.ContainsKey(ds.SeriesName))
  139. continue;
  140. if (data[ds.SeriesName] is bool)
  141. {
  142. ds.Append(dt, ((bool)data[ds.SeriesName] ? 1 : 0) * ds.Factor + ds.Offset, new ParameterNodePoint(dt, ((bool)data[ds.SeriesName] ? 1 : 0)));
  143. continue;
  144. }
  145. if (!double.TryParse(data[ds.SeriesName].ToString(), out var value))
  146. continue;
  147. ds.Append(dt, value * ds.Factor + ds.Offset, new ParameterNodePoint(dt, value));
  148. }
  149. }
  150. private void UpdateFifoCapacity(int capacity)
  151. {
  152. foreach (var renderableSeries in SelectedData)
  153. {
  154. if (renderableSeries is FastLineSeries line)
  155. {
  156. var ds = line.GetDataSeries();
  157. var copyMetaData = ds.Metadata.Where(x => x != null && ((ParameterNodePoint)x).Time > DateTime.Now.AddSeconds(-TrendTimeSpan)).ToList();
  158. ds.FifoCapacity = capacity;
  159. foreach (ParameterNodePoint item in copyMetaData)
  160. {
  161. ds.Append(item.Time, item.Value);
  162. }
  163. }
  164. }
  165. }
  166. public void SetInterval()
  167. {
  168. _thread.ChangeInterval(TrendInterval);
  169. _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
  170. IntervalSaved = true;
  171. NotifyOfPropertyChange(nameof(IntervalSaved));
  172. UpdateFifoCapacity(_pointCount);
  173. }
  174. public void SetTimeSpan()
  175. {
  176. _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
  177. TimeSpanSaved = true;
  178. NotifyOfPropertyChange(nameof(TimeSpanSaved));
  179. UpdateFifoCapacity(_pointCount);
  180. }
  181. #endregion
  182. #region Events
  183. public void OnNodeSelectionChanged(object sender, TreeNodeSelectionChangedEventArgs e)
  184. {
  185. if (e.NewValue == true && SelectedData.Count >= MAX_PARAMETERS_ALLOWED)
  186. {
  187. e.Cancel = true;
  188. return;
  189. }
  190. var line = SelectedData.Cast<FastLineSeries>().FirstOrDefault(x => x.DataName == e.Source.FullName);
  191. switch (e.NewValue)
  192. {
  193. case false:
  194. {
  195. if (line != null)
  196. {
  197. _dataSeriesList.Remove(line.GetDataSeries());
  198. SelectedData.Remove(line);
  199. }
  200. break;
  201. }
  202. case true:
  203. {
  204. if (line == null)
  205. {
  206. var series = new FastLineSeries(e.Source.FullName)
  207. {
  208. BackendParameterNode = e.Source
  209. };
  210. series.GetDataSeries().FifoCapacity = _pointCount;
  211. SelectedData.Add(series);
  212. _dataSeriesList.Add(series.GetDataSeries());
  213. SelectedData.ResetColors();
  214. }
  215. break;
  216. }
  217. default:
  218. break;
  219. }
  220. }
  221. public void Deleted(object sender, RenderableSeriesDeletingEventArgs e)
  222. {
  223. var list = e.Source.Cast<FastLineSeries>().ToList();
  224. var total = SelectedData.Count;
  225. for (var i = total - 1; i >= 0; i--)
  226. {
  227. if (i < list.Count)
  228. {
  229. list[i].BackendParameterNode.IsSelected = false;
  230. }
  231. }
  232. _dataSeriesList.Clear();
  233. ((RealtimeView)View).tvParameterNodes.ClearPresetGroupSelectionOnly();
  234. }
  235. public void Exporting(object sender, EventArgs e)
  236. {
  237. BusyIndicatorContent = "Exporting ...";
  238. IsBusy = true;
  239. }
  240. public void Exported(object sender, EventArgs e)
  241. {
  242. IsBusy = false;
  243. }
  244. public void ProgressUpdating(object sender, ProgressUpdatingEventArgs e)
  245. {
  246. _exportingProgressReporter.Report(e);
  247. }
  248. public override void Cancel()
  249. {
  250. if (View is RealtimeView view)
  251. {
  252. view.dataGrid.CancelOperation();
  253. }
  254. }
  255. public void ArrowClick(string direction)
  256. {
  257. var view = GetView() as RealtimeView;
  258. switch (direction)
  259. {
  260. case "Up":
  261. view.sciChart.ChartModifier.YAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMax);
  262. break;
  263. case "Down":
  264. view.sciChart.ChartModifier.YAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMin);
  265. break;
  266. case "Left":
  267. view.sciChart.ChartModifier.XAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMin);
  268. break;
  269. case "Right":
  270. view.sciChart.ChartModifier.XAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMax);
  271. break;
  272. }
  273. }
  274. public void ZoomInClick(int index)
  275. {
  276. var view = GetView() as RealtimeView;
  277. index += 1;
  278. if ((index & 0x01) == 1)
  279. view.sciChart.ChartModifier.XAxis.ZoomBy(-0.1, -0.1);
  280. if ((index & 0x02) == 2)
  281. view.sciChart.ChartModifier.YAxis.ZoomBy(-0.1, -0.1);
  282. }
  283. public void ZoomOutClick(int index)
  284. {
  285. var view = GetView() as RealtimeView;
  286. index += 1;
  287. if ((index & 0x01) == 1)
  288. view.sciChart.ChartModifier.XAxis.ZoomBy(0.1, 0.1);
  289. if ((index & 0x02) == 2)
  290. view.sciChart.ChartModifier.YAxis.ZoomBy(0.1, 0.1);
  291. }
  292. #endregion
  293. }
  294. }