RealTimeViewModel.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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. private bool _IsHold;
  92. public bool IsHold
  93. {
  94. get { return _IsHold; }
  95. set
  96. {
  97. if (_IsHold!=value)
  98. {
  99. _IsHold = value;
  100. if (_IsHold) EnableAutoZoom = false;
  101. else EnableAutoZoom = true;
  102. NotifyOfPropertyChange(nameof(IsHold));
  103. }
  104. }
  105. }
  106. #endregion
  107. #region Methods
  108. protected bool MonitorData()
  109. {
  110. try
  111. {
  112. Dictionary<string, object> data = new Dictionary<string, object>();
  113. if (!IsHold && SelectedData.Count > 0)
  114. {
  115. var rtData = QueryDataClient.Instance.Service.PollData(SelectedData.Select(r => FindKeyByValue(_displayDic, (r as FastLineSeries)?.DataName)).ToList());
  116. foreach (var item in rtData)
  117. {
  118. var uiName = _displayDic[item.Key];
  119. data.Add(uiName, item.Value);
  120. }
  121. AppendData(data);
  122. }
  123. for (var j = 0; j < ParameterNodes.ChildNodes.Count; j++)
  124. {
  125. var par = ParameterNodes.ChildNodes[j];
  126. par.IsVisibilityParentNode = Visibility.Hidden;
  127. }
  128. }
  129. catch (Exception ex)
  130. {
  131. LOG.Error(ex.Message);
  132. }
  133. return true;
  134. }
  135. static string FindKeyByValue(Dictionary<string, string> dictionary, string value)
  136. {
  137. foreach (var pair in dictionary)
  138. {
  139. if (pair.Value == value)
  140. {
  141. return pair.Key;
  142. }
  143. }
  144. return null; // Return null if the value is not found
  145. }
  146. public void AppendData(Dictionary<string, object> data)
  147. {
  148. if (data == null)
  149. return;
  150. var dt = DateTime.Now;
  151. foreach (var ds in _dataSeriesList)
  152. {
  153. if (ds == null || !data.ContainsKey(ds.SeriesName))
  154. continue;
  155. if (data[ds.SeriesName] is bool)
  156. {
  157. ds.Append(dt, ((bool)data[ds.SeriesName] ? 1 : 0) * ds.Factor + ds.Offset, new ParameterNodePoint(dt, ((bool)data[ds.SeriesName] ? 1 : 0)));
  158. continue;
  159. }
  160. if (!double.TryParse(data[ds.SeriesName].ToString(), out var value))
  161. continue;
  162. ds.Append(dt, value * ds.Factor + ds.Offset, new ParameterNodePoint(dt, value));
  163. }
  164. }
  165. private void UpdateFifoCapacity(int capacity)
  166. {
  167. foreach (var renderableSeries in SelectedData)
  168. {
  169. if (renderableSeries is FastLineSeries line)
  170. {
  171. var ds = line.GetDataSeries();
  172. var copyMetaData = ds.Metadata.Where(x => x != null && ((ParameterNodePoint)x).Time > DateTime.Now.AddSeconds(-TrendTimeSpan)).ToList();
  173. ds.FifoCapacity = capacity;
  174. foreach (ParameterNodePoint item in copyMetaData)
  175. {
  176. ds.Append(item.Time, item.Value);
  177. }
  178. }
  179. }
  180. }
  181. public void SetInterval()
  182. {
  183. _thread.ChangeInterval(TrendInterval);
  184. _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
  185. IntervalSaved = true;
  186. NotifyOfPropertyChange(nameof(IntervalSaved));
  187. UpdateFifoCapacity(_pointCount);
  188. }
  189. public void SetTimeSpan()
  190. {
  191. _pointCount = Math.Max(10, TrendTimeSpan * 1000 / TrendInterval);
  192. TimeSpanSaved = true;
  193. NotifyOfPropertyChange(nameof(TimeSpanSaved));
  194. UpdateFifoCapacity(_pointCount);
  195. }
  196. #endregion
  197. #region Events
  198. public void OnNodeSelectionChanged(object sender, TreeNodeSelectionChangedEventArgs e)
  199. {
  200. if (e.NewValue == true && SelectedData.Count >= MAX_PARAMETERS_ALLOWED)
  201. {
  202. e.Cancel = true;
  203. return;
  204. }
  205. var line = SelectedData.Cast<FastLineSeries>().FirstOrDefault(x => x.DataName == e.Source.FullName);
  206. switch (e.NewValue)
  207. {
  208. case false:
  209. {
  210. if (line != null)
  211. {
  212. _dataSeriesList.Remove(line.GetDataSeries());
  213. SelectedData.Remove(line);
  214. }
  215. break;
  216. }
  217. case true:
  218. {
  219. if (line == null)
  220. {
  221. var series = new FastLineSeries(e.Source.FullName)
  222. {
  223. BackendParameterNode = e.Source
  224. };
  225. series.GetDataSeries().FifoCapacity = _pointCount;
  226. SelectedData.Add(series);
  227. _dataSeriesList.Add(series.GetDataSeries());
  228. SelectedData.ResetColors();
  229. }
  230. break;
  231. }
  232. default:
  233. break;
  234. }
  235. }
  236. public void Deleted(object sender, RenderableSeriesDeletingEventArgs e)
  237. {
  238. var list = e.Source.Cast<FastLineSeries>().ToList();
  239. var total = SelectedData.Count;
  240. for (var i = total - 1; i >= 0; i--)
  241. {
  242. if (i < list.Count)
  243. {
  244. list[i].BackendParameterNode.IsSelected = false;
  245. }
  246. }
  247. _dataSeriesList.Clear();
  248. ((RealtimeView)View).tvParameterNodes.ClearPresetGroupSelectionOnly();
  249. }
  250. public void Exporting(object sender, EventArgs e)
  251. {
  252. BusyIndicatorContent = "Exporting ...";
  253. IsBusy = true;
  254. }
  255. public void Exported(object sender, EventArgs e)
  256. {
  257. IsBusy = false;
  258. }
  259. public void ProgressUpdating(object sender, ProgressUpdatingEventArgs e)
  260. {
  261. _exportingProgressReporter.Report(e);
  262. }
  263. public override void Cancel()
  264. {
  265. if (View is RealtimeView view)
  266. {
  267. view.dataGrid.CancelOperation();
  268. }
  269. }
  270. public void ArrowClick(string direction)
  271. {
  272. var view = GetView() as RealtimeView;
  273. switch (direction)
  274. {
  275. case "Up":
  276. view.sciChart.ChartModifier.YAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMax);
  277. break;
  278. case "Down":
  279. view.sciChart.ChartModifier.YAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMin);
  280. break;
  281. case "Left":
  282. view.sciChart.ChartModifier.XAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMin);
  283. break;
  284. case "Right":
  285. view.sciChart.ChartModifier.XAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMax);
  286. break;
  287. }
  288. }
  289. public void ZoomInClick(int index)
  290. {
  291. var view = GetView() as RealtimeView;
  292. index += 1;
  293. if ((index & 0x01) == 1)
  294. view.sciChart.ChartModifier.XAxis.ZoomBy(-0.1, -0.1);
  295. if ((index & 0x02) == 2)
  296. view.sciChart.ChartModifier.YAxis.ZoomBy(-0.1, -0.1);
  297. }
  298. public void ZoomOutClick(int index)
  299. {
  300. var view = GetView() as RealtimeView;
  301. index += 1;
  302. if ((index & 0x01) == 1)
  303. view.sciChart.ChartModifier.XAxis.ZoomBy(0.1, 0.1);
  304. if ((index & 0x02) == 2)
  305. view.sciChart.ChartModifier.YAxis.ZoomBy(0.1, 0.1);
  306. }
  307. #endregion
  308. }
  309. }