RealTimeViewModel.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. namespace MECF.Framework.UI.Client.CenterViews.Operations.RealTime
  22. {
  23. public class RealtimeViewModel : BusyIndicateableUiViewModelBase
  24. {
  25. #region Variables
  26. /// <summary>
  27. /// 允许监控的最大曲线数量
  28. /// </summary>
  29. private const int MAX_PARAMETERS_ALLOWED = 200;
  30. private readonly RealtimeProvider _provider = new RealtimeProvider();
  31. private bool _enableAutoZoom = true;
  32. private int _pointCount;
  33. private readonly PeriodicJob _thread;
  34. /// <summary>
  35. /// Monitor中添加数据点时直接向DataSeries对象添加,已实现跨线程操作。
  36. /// </summary>
  37. private readonly List<FastLineDataSeries> _dataSeriesList;
  38. /// <summary>
  39. /// 更新报告导出信息。
  40. /// </summary>
  41. private readonly IProgress<ProgressUpdatingEventArgs> _exportingProgressReporter;
  42. #endregion
  43. #region Constructors
  44. public RealtimeViewModel()
  45. {
  46. DisplayName = "Realtime";
  47. SelectedData = new ChartingLineSeriesCollection(DisplayName);
  48. ParameterNodes = new TreeNode(DisplayName)
  49. {
  50. MaxTerminalSelectionAllowed = MAX_PARAMETERS_ALLOWED
  51. };
  52. ParameterNodes.ChildNodes.AddRange(_provider.GetTreeNodeParameters());
  53. ParameterNodes.TerminalNodeSelectionChanged += OnNodeSelectionChanged;
  54. IntervalSaved = true;
  55. TrendInterval = 500;
  56. TimeSpanSaved = true;
  57. TrendTimeSpan = 60 * 5;
  58. _thread = new PeriodicJob(TrendInterval, MonitorData, "RealTime", true);
  59. _pointCount = Math.Max(TrendTimeSpan * 1000 / TrendInterval, 10);
  60. _dataSeriesList = new List<FastLineDataSeries>();
  61. _exportingProgressReporter = new Progress<ProgressUpdatingEventArgs>(e =>
  62. {
  63. BusyIndicatorContent = e.Message;
  64. });
  65. }
  66. #endregion
  67. #region Properties
  68. public bool IsPermission => this.Permission == 3;
  69. public TreeNode ParameterNodes { get; }
  70. public ChartingLineSeriesCollection SelectedData { get; set; }
  71. public AutoRange ChartAutoRange => EnableAutoZoom ? AutoRange.Always : AutoRange.Never;
  72. public bool EnableAutoZoom
  73. {
  74. get => _enableAutoZoom;
  75. set
  76. {
  77. _enableAutoZoom = value;
  78. NotifyOfPropertyChange(nameof(EnableAutoZoom));
  79. NotifyOfPropertyChange(nameof(ChartAutoRange));
  80. }
  81. }
  82. [IgnorePropertyChange]
  83. public int TrendInterval { get; set; }
  84. public bool IntervalSaved { get; set; }
  85. [IgnorePropertyChange]
  86. public int TrendTimeSpan { get; set; }
  87. public bool TimeSpanSaved { get; set; }
  88. #endregion
  89. #region Methods
  90. protected bool MonitorData()
  91. {
  92. try
  93. {
  94. Dictionary<string, object> data = null;
  95. if (SelectedData.Count > 0)
  96. {
  97. data = QueryDataClient.Instance.Service.PollData(Array.ConvertAll(SelectedData.ToArray(), x => (x as FastLineSeries).DataName));
  98. }
  99. AppendData(data);
  100. for (var j = 0; j < ParameterNodes.ChildNodes.Count; j++)
  101. {
  102. var par = ParameterNodes.ChildNodes[j];
  103. par.IsVisibilityParentNode = Visibility.Hidden;
  104. }
  105. }
  106. catch (Exception ex)
  107. {
  108. LOG.Error(ex.Message);
  109. }
  110. return true;
  111. }
  112. public void AppendData(Dictionary<string, object> data)
  113. {
  114. if (data == null)
  115. return;
  116. var dt = DateTime.Now;
  117. foreach (var ds in _dataSeriesList)
  118. {
  119. if (ds == null || !data.ContainsKey(ds.SeriesName))
  120. continue;
  121. if (data[ds.SeriesName] is bool)
  122. {
  123. ds.Append(dt, ((bool)data[ds.SeriesName] ? 1 : 0) * ds.Factor + ds.Offset, new ParameterNodePoint(dt, ((bool)data[ds.SeriesName] ? 1 : 0)));
  124. continue;
  125. }
  126. if (!double.TryParse(data[ds.SeriesName].ToString(), out var value))
  127. continue;
  128. ds.Append(dt, value * ds.Factor + ds.Offset, new ParameterNodePoint(dt, value));
  129. }
  130. }
  131. private void UpdateFifoCapacity(int capacity)
  132. {
  133. foreach (var renderableSeries in SelectedData)
  134. {
  135. if (renderableSeries is FastLineSeries line)
  136. {
  137. var ds = line.GetDataSeries();
  138. var copyMetaData = ds.Metadata.Where(x => x != null && ((ParameterNodePoint)x).Time > DateTime.Now.AddSeconds(-TrendTimeSpan)).ToList();
  139. ds.FifoCapacity = capacity;
  140. foreach (ParameterNodePoint item in copyMetaData)
  141. {
  142. ds.Append(item.Time, item.Value);
  143. }
  144. }
  145. }
  146. }
  147. public void SetInterval()
  148. {
  149. _thread.ChangeInterval(TrendInterval);
  150. _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
  151. IntervalSaved = true;
  152. NotifyOfPropertyChange(nameof(IntervalSaved));
  153. UpdateFifoCapacity(_pointCount);
  154. }
  155. public void SetTimeSpan()
  156. {
  157. _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
  158. TimeSpanSaved = true;
  159. NotifyOfPropertyChange(nameof(TimeSpanSaved));
  160. UpdateFifoCapacity(_pointCount);
  161. }
  162. #endregion
  163. #region Events
  164. public void OnNodeSelectionChanged(object sender, TreeNodeSelectionChangedEventArgs e)
  165. {
  166. if (e.NewValue == true && SelectedData.Count >= MAX_PARAMETERS_ALLOWED)
  167. {
  168. e.Cancel = true;
  169. return;
  170. }
  171. var line = SelectedData.Cast<FastLineSeries>().FirstOrDefault(x => x.DataName == e.Source.FullName);
  172. switch (e.NewValue)
  173. {
  174. case false:
  175. {
  176. if (line != null)
  177. {
  178. _dataSeriesList.Remove(line.GetDataSeries());
  179. SelectedData.Remove(line);
  180. }
  181. break;
  182. }
  183. case true:
  184. {
  185. if (line == null)
  186. {
  187. var series = new FastLineSeries(e.Source.FullName)
  188. {
  189. BackendParameterNode = e.Source
  190. };
  191. series.GetDataSeries().FifoCapacity = _pointCount;
  192. SelectedData.Add(series);
  193. _dataSeriesList.Add(series.GetDataSeries());
  194. SelectedData.ResetColors();
  195. }
  196. break;
  197. }
  198. default:
  199. break;
  200. }
  201. }
  202. public void Deleted(object sender, RenderableSeriesDeletingEventArgs e)
  203. {
  204. var list = e.Source.Cast<FastLineSeries>().ToList();
  205. var total = SelectedData.Count;
  206. for (var i = total - 1; i >= 0; i--)
  207. {
  208. if (i < list.Count)
  209. {
  210. list[i].BackendParameterNode.IsSelected = false;
  211. }
  212. }
  213. _dataSeriesList.Clear();
  214. ((RealtimeView)View).tvParameterNodes.ClearPresetGroupSelectionOnly();
  215. }
  216. public void Exporting(object sender, EventArgs e)
  217. {
  218. BusyIndicatorContent = "Exporting ...";
  219. IsBusy = true;
  220. }
  221. public void Exported(object sender, EventArgs e)
  222. {
  223. IsBusy = false;
  224. }
  225. public void ProgressUpdating(object sender, ProgressUpdatingEventArgs e)
  226. {
  227. _exportingProgressReporter.Report(e);
  228. }
  229. public override void Cancel()
  230. {
  231. if (View is RealtimeView view)
  232. {
  233. view.dataGrid.CancelOperation();
  234. }
  235. }
  236. #endregion
  237. }
  238. }