using Arction.Wpf.Charting; using Arction.Wpf.Charting.Axes; using Arction.Wpf.Charting.SeriesXY; using Arction.Wpf.Charting.Views.ViewXY; using Microsoft.Win32; using Prism.Commands; using Prism.Mvvm; using Prism.Regions; using ServiceStack; using StartServerWPF.Assets; using StartServerWPF.Modules.MseedChart.Models; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Threading; using System.Xml.Linq; using ZhaoXi.Advanced.MyRedis.Service; namespace StartServerWPF.Modules.MseedChart.ViewModels { public class ChartPlotRealDataViewModel : BindableBase, INavigationAware { Mseed2asciiApi.LoopCallbackHandler loopCallback; public ChartPlotRealDataViewModel() { _dispatcher = Application.Current.Dispatcher; _wavesModel = new WavesModel(); (Application.Current.MainWindow as System.Windows.Window).Closing += ApplicationClosingDispose; IntervalTime=1000; CreateChart(); loopCallback = new Mseed2asciiApi.LoopCallbackHandler(Mseed2AsciiEvent); Mseed2asciiApi.MseedDatasCallFun(loopCallback); GC.KeepAlive(loopCallback); } #region 字段 System.Timers.Timer time=new System.Timers.Timer(1000); Dispatcher _dispatcher; public int CurPoints; int _channelCount = 0; int _samplingFrequency = 500; // 采样频率 (Hz). WavesModel _wavesModel; private int _lChartCount = 1; public ConcurrentQueue smList=new ConcurrentQueue(); public List _chartAxisY=new List(); // Dictionary cacheChartDic=new Dictionary(); Dictionary subNameList; #endregion #region 属性 private string _title = "数据中心"; public string Title { get { return _title; } set { SetProperty(ref _title, value); } } private bool _isRealtimeData =false; public bool IsRealtimeData { get { return _isRealtimeData; } set { SetProperty(ref _isRealtimeData, value); } } private bool _isMultFiles; public bool IsMultFiles { get { return _isMultFiles; } set { SetProperty(ref _isMultFiles, value); } } private int _xaisInterval; public int XaisInterval { get { return _xaisInterval; } set { SetProperty(ref _xaisInterval, value); } } /// /// 波形控件数量 /// public int LChartCount { get { return _lChartCount; } set { _lChartCount = value; } } private LightningChart _lChartAll; /// /// 所有波形 /// public LightningChart LChartALL { get { return _lChartAll; } set { _lChartAll = value; } } private FrameworkElement childContent; public FrameworkElement ChildContent { get { return childContent; } set { childContent = value; } } private Grid gridChart; public Grid GridChart { get { return gridChart; } set { gridChart = value; } } private StationEventJson _currentEventTime; public StationEventJson CurrentEventTime { get { return _currentEventTime; } set { _currentEventTime = value; } } private List _stationsName; public List StationsName { get { return _stationsName; } set { SetProperty(ref _stationsName, value); } } private string _currentTime; public string CurrentTime { get { return _currentTime; } set { SetProperty(ref _currentTime, value); } } private YAxisAutoPlacement _yaxisPlacement; public YAxisAutoPlacement YaxisPlacement { get { return _yaxisPlacement; } set { LChartALL.ViewXY.AxisLayout.YAxisAutoPlacement = value; int distancetoX =_wavesModel.SetYasixPlacement(LChartALL); foreach (var item in LChartALL.ViewXY.YAxes) { item.Title.DistanceToAxis = distancetoX; } SetProperty(ref _yaxisPlacement, value); } } private int _IntervalTime=1000; public int IntervalTime { get { return _IntervalTime; } set { if (value >=10) { // time.Interval = value; } SetProperty(ref _IntervalTime, value); } } private bool _SingleChannel=false; public bool SingleChannel { get { return _SingleChannel; } set { if(!value) { YasixZENVisible("SHZ", false); YasixZENVisible("SHN", false); YasixZENVisible("SHE", false); } else { YasixZENVisible("SHZ", true); YasixZENVisible("SHN", true); YasixZENVisible("SHE", true); YasixZENVisible(SelectChannel, false); } SetProperty(ref _SingleChannel, value); } } private string _SelectChannel; public string SelectChannel { get { return _SelectChannel; } set { if (SingleChannel) { //隐藏上当前轴 YasixZENVisible(_SelectChannel, true); //显示选择轴 YasixZENVisible(value, false); } SetProperty(ref _SelectChannel, value); } } #endregion #region 事件 public DelegateCommand LoadedCommand => new DelegateCommand(Loaded); public DelegateCommand UnloadedCommand => new DelegateCommand(UnLoaded); public DelegateCommand AxesYVisibleCommand => new DelegateCommand(AxesYVisible); public DelegateCommand FileSelectorCommand => new DelegateCommand(FileSelector); public DelegateCommand OtimeSortCommand => new DelegateCommand(OtimeSort); public DelegateCommand IntervalSureCommand => new DelegateCommand(IntervalSure); public DelegateCommand RealTimeDataCommand => new DelegateCommand(RealTimeData); private void Loaded() { //N08,N25,N26 var stations = GlobalData.StationNames;// station.Split(','); smList = _wavesModel.ReadWavesFromJson(stations); subNameList = new Dictionary(); } private void UnLoaded() { time.Stop(); if(subNameList == null) return; foreach (var subName in subNameList) { using (RedisListService service = new RedisListService()) { //停止订阅 service.Publish(subName.Key, "shutoff"); } } } private void AxesYVisible(object isCheck) { if (_lChartAll != null) { bool yAxesVisible = ((bool)isCheck == true); _lChartAll.BeginUpdate(); foreach (AxisY yAxis in _lChartAll.ViewXY.YAxes) { yAxis.Visible = yAxesVisible; } _lChartAll.EndUpdate(); } } private void FileSelector(object obj) { IsMultFiles = Convert.ToBoolean(obj); OpenFileDialog openFileDialog = new OpenFileDialog { RestoreDirectory = true, Filter = ".mseed|*.mseed|.json|*.json|.txt|*.txt", }; if (openFileDialog.ShowDialog() == true) { string asciiSavePath = openFileDialog.FileName.Replace("Mseed", "Txt"); asciiSavePath = Path.ChangeExtension(asciiSavePath, ".txt"); string JsonPath = Path.ChangeExtension(openFileDialog.FileName, "Json"); Stopwatch st = new Stopwatch(); st.Start(); //读取.json文件 CurrentEventTime = _wavesModel.ReadChartJsonFile(JsonPath); //读取.mseed文件 smList = _wavesModel.ReadMseedFile(openFileDialog.FileName, asciiSavePath, IsMultFiles); _channelCount = smList.Count * 3; CurrentTime = smList.First().BeginTime.ToShortDateString(); StationsName = smList.Select(a => new StationAxis{Name= a.Name,IsChecked=true,SelectCommand =new DelegateCommand(StationsNameVisible)}).ToList(); StartChart(); st.Stop(); Debug.WriteLine("统计时间StartChart************:{0}", st.Elapsed); FeedDatasToChart(); if (CurrentEventTime != null) { _wavesModel.CreateAxisYEventTime(CurrentEventTime, LChartALL.ViewXY, smList.ToList()); } } } private void OtimeSort(object isCheck) { if (_lChartAll != null&& (_chartAxisY.Count!=0)) { LChartALL.BeginUpdate(); bool yAxesVisible = ((bool)isCheck == true); ViewXY v = _lChartAll.ViewXY; IOrderedEnumerable lines; if (yAxesVisible) { lines = v.LineCollections.Where(a => a.Tag != null && a.Tag.ToString().Contains("SHZ")).OrderBy(a => a.Lines[0].AX); } else { lines = v.LineCollections.Where(a => a.Tag != null && a.Tag.ToString().Contains("SHZ")).OrderByDescending(b => b.Lines[0].AX); ; } int number = v.YAxes.Count / (_chartAxisY.Count / 3); foreach (var item in lines.Reverse()) { int index = item.AssignYAxisIndex; for (int i = 0; i < number; i++) { if (index == -1) continue; //隐藏轴不需要处理 AxisY axisY = v.YAxes[index + i]; v.YAxes.RemoveAt(index + i); v.YAxes.Insert(i, axisY); } } LChartALL.EndUpdate(); } } /// /// Y轴的显示和隐藏 /// /// SHZ,SHN,SHE /// true 隐藏轴,false显示轴 private void YasixZENVisible(string content, bool yAxesVisible) { if (_lChartAll != null) { _lChartAll.BeginUpdate(); ViewXY v = _lChartAll.ViewXY; string conStr = (content == "SHZ") ? ".Z" : (content == "SHN") ? ".N" : ".E"; for (int i = 0; i <_chartAxisY.Count; i++) { AxisY axisY = _chartAxisY[i]; if (axisY.Title.Text.Contains(conStr)) { if (yAxesVisible) { //隐藏轴 v.YAxes.Remove(axisY); } else { //显示轴 var axis= v.YAxes.Where(y => y.Title.Text==axisY.Title.Text).FirstOrDefault(); if (axis != null) { //找到相同的轴不用处理 continue; } string str = axisY.Title.Text.Replace(conStr, ""); int yIndex = 0; if (content == "SHZ") { yIndex = v.YAxes.FindIndex(y => y.Title.Text.Contains(str)); } else if (content == "SHE") { yIndex = v.YAxes.FindLastIndex(y => y.Title.Text.Contains(str)); if (yIndex != -1) yIndex += 1; } else { yIndex = v.YAxes.FindIndex(y => y.Title.Text.Contains(str)); if (yIndex != -1) { if (v.YAxes[yIndex].Title.Text.Contains(".Z")) { yIndex = yIndex + 1; } } } //如果没有查到,直接添加到前面,如果为容器最大索引,只能添加到后面 if (yIndex == -1 || (yIndex == v.YAxes.Count)) { yIndex = v.YAxes.Count; v.YAxes.Add(axisY); } else { v.YAxes.Insert(yIndex, axisY); } int sampleIndex = v.SampleDataSeries.FindIndex(y => y.Title.Text == _chartAxisY[i].Title.Text); v.SampleDataSeries[sampleIndex].AssignYAxisIndex = yIndex; int lineIndex = v.LineCollections.FindIndex(a => a.Title.Text.Contains(_chartAxisY[i].Title.Text)); if (lineIndex != -1) { v.LineCollections[lineIndex].AssignYAxisIndex = yIndex; } } } } _lChartAll.EndUpdate(); } } private void IntervalSure() { if (_lChartAll != null) { _lChartAll.BeginUpdate(); if (XaisInterval >= 2) { _lChartAll.ViewXY.XAxes[0].MajorDivCount = XaisInterval; } _lChartAll.EndUpdate(); } } private void StationsNameVisible(object obj) { var station = obj as StationAxis; if (_lChartAll != null) { _lChartAll.BeginUpdate(); bool yAxesVisible = (station.IsChecked == false); ViewXY v = _lChartAll.ViewXY; var yAxisList= _chartAxisY.Where(y => y.Title.Text.Contains(station.Name)); foreach (var item in yAxisList) { if (yAxesVisible) { v.YAxes.Remove(item); } else { v.YAxes.Add(item); //SampleDataSeries查找数据对应的Y轴索引, 重新分配到对应的轴 int sampleIndex = v.SampleDataSeries.FindIndex(s => s.Title.Text == item.Title.Text); v.SampleDataSeries[sampleIndex].AssignYAxisIndex = v.YAxes.Count()-1; //LineCollections查找数据对应的Y轴索引, 重新分配到对应的轴 int lineIndex = v.LineCollections.FindIndex(s => s.Title.Text.Contains(item.Title.Text)); if (lineIndex != -1) { v.LineCollections[lineIndex].AssignYAxisIndex = v.YAxes.Count() - 1; } } } _lChartAll.EndUpdate(); } } int i = 1; private void RealTimeData(object isCheck) { _channelCount = smList.Count * 3; CurrentTime = smList.First().BeginTime.ToShortDateString(); StationsName = smList.Select(a => new StationAxis { Name = a.Name, IsChecked = true, SelectCommand = new DelegateCommand(StationsNameVisible) }).ToList(); if (_lChartAll != null) { bool isStartRealData = (Convert.ToBoolean(isCheck) == true); if (smList.Count == 0) { return; } _lChartAll.BeginUpdate(); if (isStartRealData) { currentOATime = 0; _data = new double[smList.Count * 3][]; StartChart(); //Set real-time monitoring automatic old data destruction LChartALL.ViewXY.DropOldSeriesData = true; _pointsAppended = LChartALL.ViewXY.XAxes[0].Minimum; time.Elapsed -= CompositionTarget_Rendering; time.Elapsed += CompositionTarget_Rendering; LChartALL.ViewXY.XAxes[0].ScrollMode = XAxisScrollMode.Scrolling; Task.Run(() => { Thread.Sleep(5000); time.Start(); }); using (RedisListService service = new RedisListService()) { service.FlushAll(); } foreach (var subName in subNameList) { Task.Run(() => { using (RedisListService service = new RedisListService()) { Debug.WriteLine($"注册{1}:{subName.Key}"); { service.Subscribe(subName.Key, (c, message, iRedisSubscription) => { if(message.Length==7 && System.Text.Encoding.Default.GetString(message)== "shutoff") { iRedisSubscription.UnSubscribeFromChannels(subName.Key); } Mseed2asciiApi.bufferMseedData(message.Length, message); }); } } }); } } else { time.Stop(); time.Elapsed -= CompositionTarget_Rendering; LChartALL.ViewXY.XAxes[0].ScrollMode = XAxisScrollMode.None; foreach (var subName in subNameList) { using (RedisListService service = new RedisListService()) { service.Publish(subName.Key, "shutoff"); } } } _lChartAll.EndUpdate(); } } private void Mseed2AsciiEvent(AsciiDataStruct asciiData) { DateTime startTime = Convert.ToDateTime(asciiData.endtime).AddHours(8); DateTime endTime = Convert.ToDateTime(asciiData.endtime).AddHours(8); byte[] bytes = new byte[asciiData.numsamples * asciiData.samplesize]; // IntPtr bufferHandler = Marshal.AllocHGlobal((int)asciiData.datasize); Marshal.Copy(asciiData.datasamples, bytes, 0, bytes.Length); List lines = new List(); //时间添加到开始 lines.Add(startTime.ToOADate()); string[] sid = asciiData.sid.Split('_'); string name = $"HA.{sid[1]}.{sid[2]}.{sid[3]}{sid[4]}{sid[5]}"; if (asciiData.sampletype == 'i') { for (int index = 0; index < bytes.Length; index += 4) { var a = BitConverter.ToInt32(bytes, index); lines.Add(a); } } else if (asciiData.sampletype == 'f') { for (int index = 0; index < bytes.Length; index += 4) { var b = BitConverter.ToSingle(bytes, index); lines.Add(b); } } else if (asciiData.sampletype == 'd') { for (int index = 0; index < bytes.Length; index += 8) { var b = BitConverter.ToDouble(bytes, index); lines.Add(b); } } Debug.WriteLine($"接收:{asciiData.sid}:{startTime},count:{lines.Count}"); string lineStr = String.Join(",", lines); using (RedisListService service = new RedisListService()) { service.LPush(name, lineStr); } } #endregion private void CreateChart() { if (LChartALL != null) { LChartALL = null; } LChartALL = new LightningChart(); LChartALL.Title.Align = ChartTitleAlignment.TopCenter; LChartALL.ChartRenderOptions.DeviceType = RendererDeviceType.AutoPreferD11; LChartALL.ChartRenderOptions.LineAAType2D = LineAntiAliasingType.QLAA; LChartALL.Title.Text = "事件波形"; LChartALL.Title.Font = new WpfFont("等线", 20); //轴属性和布局 LChartALL.ViewXY.AxisLayout.YAxesLayout = YAxesLayout.Stacked; LChartALL.ViewXY.AxisLayout.SegmentsGap = 0; LChartALL.ViewXY.ZoomPanOptions.PanDirection = PanDirection.Horizontal; LChartALL.ViewXY.ZoomPanOptions.WheelZooming = WheelZooming.Horizontal; LChartALL.ViewXY.AxisLayout.YAxisAutoPlacement = YAxisAutoPlacement.AllRight; LChartALL.ViewXY.AxisLayout.YAxisTitleAutoPlacement = false; LChartALL.ViewXY.AxisLayout.AutoAdjustMargins = false; LChartALL.ViewXY.ZoomPanOptions.DevicePrimaryButtonAction = UserInteractiveDeviceButtonAction.Pan; LChartALL.ViewXY.ZoomPanOptions.DeviceSecondaryButtonAction = UserInteractiveDeviceButtonAction.None; LChartALL.ViewXY.ZoomPanOptions.WheelZooming = WheelZooming.Horizontal; // 反锯齿系数。值0和1都不会应用反锯齿 LChartALL.ChartRenderOptions.AntiAliasLevel = 0; //X轴设置 LChartALL.ViewXY.XAxes[0].AllowScrolling = true; LChartALL.ViewXY.XAxes[0].PanningEnabled = true; LChartALL.ViewXY.XAxes[0].MajorGrid.Pattern = LinePattern.Solid; LChartALL.ViewXY.XAxes[0].ValueType = AxisValueType.DateTime; LChartALL.ViewXY.XAxes[0].KeepDivCountOnRangeChange = true; //LChartALL.ViewXY.XAxes[0].MajorDiv =6; LChartALL.ViewXY.XAxes[0].LabelsColor = Colors.Black; LChartALL.ViewXY.XAxes[0].AutoDivSpacing = false; LChartALL.ViewXY.XAxes[0].MajorDivCount = 5; XaisInterval = 5; //图表背景颜色 LChartALL.ViewXY.GraphBackground.Color = Colors.White; LChartALL.ViewXY.GraphBackground.GradientColor = Colors.White; LChartALL.ChartBackground.GradientFill = GradientFill.Solid; LChartALL.ChartBackground.Color = Color.FromArgb(0, 0, 0, 0); GridChart = new Grid(); GridChart.ColumnDefinitions.Add(new ColumnDefinition()); GridChart.Name = "chartGrid"; GridChart.Children.Add(LChartALL); this.ChildContent = GridChart; } private void StartChart() { DisposeAllAndClear(_chartAxisY); ViewXY v = LChartALL.ViewXY; LChartALL.SizeChanged -= LChartALL_SizeChanged; LChartALL.SizeChanged += LChartALL_SizeChanged; LChartALL.ViewXY.Zoomed -= ViewXY_Zoomed; LChartALL.ViewXY.Zoomed += ViewXY_Zoomed; LChartALL.ViewXY.Panned -= ViewXY_Panned; LChartALL.ViewXY.Panned += ViewXY_Panned; DisposeAllAndClear(v.YAxes); DisposeAllAndClear(v.SampleDataSeries); DisposeAllAndClear(v.LineCollections); v.Margins=new Thickness(60, 30, 60, 60); v.YAxes.AddRange(_wavesModel.CreateYAxisChart(smList.ToList(), LChartALL)); v.LegendBoxes[0].Position = LegendBoxPositionXY.RightCenter; v.LegendBoxes[0].Offset.SetValues(-10, 180); v.LegendBoxes[0].Layout = LegendBoxLayout.Vertical; v.LegendBoxes[0].Visible = false; v.LegendBoxes[0].Shadow.Color = Colors.Transparent; v.LegendBoxes[0].BorderColor = Colors.Transparent; v.AutoSpaceLegendBoxes = true; v.AxisLayout.SegmentsGap = 3; v.LegendBoxes[0].Shadow.Visible = false; StationModel stationModel = smList.First(); var beginTime= stationModel.BeginTime; if (AxisValueType.DateTime == v.XAxes[0].ValueType) { //设置X轴的开始时间 v.XAxes[0].AutoFormatLabels = false; v.XAxes[0].LabelsTimeFormat = "HH:mm:ss.ff"; v.XAxes[0].DateOriginYear = beginTime.Year; v.XAxes[0].DateOriginDay = beginTime.Day; v.XAxes[0].DateOriginMonth = beginTime.Month; DateTime MaxDateTime = beginTime.AddSeconds(_samplingFrequency == 500 ? 30 : 60); v.XAxes[0].SetRange(v.XAxes[0].DateTimeToAxisValue(beginTime), v.XAxes[0].DateTimeToAxisValue(MaxDateTime)); } double firstSampleTimeStamp = v.XAxes[0].DateTimeToAxisValue(beginTime); int count = stationModel.Dzne.Count; int number= smList.Count*3; bool isAdd = false; if (subNameList.Count == 0) { isAdd = true; } for (int i = 0; i < number; i++) { int seriesIndex = i; AxisY axisY = v.YAxes[seriesIndex]; axisY.LabelsColor = Colors.Black; axisY.Title.Shadow.DropColor = Colors.Transparent; // axisY.Title.Shadow.ContrastColor = Colors.Transparent; axisY.Title.AllowDragging = true; axisY.AllowAutoYFit = true; axisY.Units.Visible = false; axisY.LabelsFont.Size = 10; axisY.Title.Angle = 0; axisY.MinorGrid.Visible = false; axisY.AutoDivSpacing = false; axisY.MajorDivCount = 2; // axisY.MajorDiv = 1; axisY.MinorDivTickStyle.Visible = false; axisY.MajorGrid.Visible = true; axisY.MajorGrid.Pattern = LinePattern.Solid; axisY.MajorDivTickStyle.Alignment = seriesIndex % 2 == 0 ? Alignment.Near : Alignment.Far; // axisY.MajorDivTickStyle.LineLength = 6; axisY.MajorDivTickStyle.Color = Colors.Black; axisY.Title.Color = Colors.Black; axisY.Title.Font = new WpfFont("Segoe UI", 10, false, false); axisY.PanningEnabled = false; axisY.AllowScrolling = true; axisY.AllowScaling = true; SampleDataSeries series = new SampleDataSeries(v, v.XAxes[0], axisY); series.ShowInLegendBox = false; series.FirstSampleTimeStamp = firstSampleTimeStamp; series.SamplingFrequency = _samplingFrequency; series.Title.Text = axisY.Title.Text; series.SampleFormat = SampleFormat.DoubleFloat; string subName = string.Empty; string name = axisY.Title.Text.Substring(2,3); if (seriesIndex % 3 == 0) { subName = $"HA.{name}.06.SHZ"; series.LineStyle.Color = System.Windows.Media.Colors.DeepSkyBlue; } else if (seriesIndex % 3 == 1) { subName = $"HA.{name}.06.SHN"; series.LineStyle.Color = System.Windows.Media.Colors.OrangeRed; } else if (seriesIndex % 3 == 2) { subName = $"HA.{name}.06.SHE"; series.LineStyle.Color = System.Windows.Media.Colors.ForestGreen; } if (isAdd) { subNameList.Add(subName, new ASCiiData { Index = i, sid = subName }); } series.LineStyle.Width = 0.2; series.ScrollModePointsKeepLevel = 1; //series.ScrollingStabilizing = true; v.SampleDataSeries.Add(series); _chartAxisY.Add(axisY); } } private void ViewXY_Panned(object sender, PannedXYEventArgs e) { foreach (var item in LChartALL.ViewXY.LineCollections) { double b = LChartALL.ViewXY.XAxes[0].ValueToCoordD(item.Lines[0].AX) - 80; item.Title.Offset.SetValues((int)b, 3); } } private void ViewXY_Zoomed(object sender, ZoomedXYEventArgs e) { foreach (var item in LChartALL.ViewXY.LineCollections) { double b = LChartALL.ViewXY.XAxes[0].ValueToCoordD(item.Lines[0].AX) - 80; item.Title.Offset.SetValues((int)b, 3); } } private void LChartALL_SizeChanged(object sender, SizeChangedEventArgs e) { int distancetoX = _wavesModel.SetYasixPlacement(LChartALL); foreach (var item in LChartALL.ViewXY.YAxes) { item.Title.DistanceToAxis = distancetoX; } foreach (var item in LChartALL.ViewXY.LineCollections) { double b = LChartALL.ViewXY.XAxes[0].ValueToCoordD(item.Lines[0].AX)-80; item.Title.Offset.SetValues((int)b, 3); } } private void FeedDatasToChart() { _data = new double[smList.Count * 3][]; try { for (int channelIndex = 0; channelIndex < smList.Count; channelIndex++) { _data[channelIndex * 3] = smList.ElementAt(channelIndex).dz.ToArray(); _data[channelIndex * 3 + 1] = smList.ElementAt(channelIndex).dn.ToArray(); _data[channelIndex * 3 + 2] = smList.ElementAt(channelIndex).de.ToArray(); } // Invoke FeedNewDataToChart. _dispatcher.Invoke(() => { LChartALL.BeginUpdate(); for (int channelIndex = 0; channelIndex < _channelCount; channelIndex++) { LChartALL.ViewXY.SampleDataSeries[channelIndex].AddSamples(_data[channelIndex], true); } LChartALL.EndUpdate(); }); } catch (Exception ex) { throw ex; } } private void ApplicationClosingDispose(object sender, CancelEventArgs e) { if (LChartALL != null) { LChartALL.Dispose(); LChartALL = null; } } private void DisposeAllAndClear(List list) where T : IDisposable { if (list == null) { return; } while (list.Count > 0) { int lastInd = list.Count - 1; T item = list[lastInd]; // take item ref from list. list.RemoveAt(lastInd); // remove item first if (item != null) { (item as IDisposable).Dispose(); // then dispose it. } } } public void Dispose() { gridChart.Children.Clear(); if (LChartALL != null) { LChartALL.Dispose(); LChartALL = null; } } #region 实时数据 private void CompositionTarget_Rendering(object sender, System.Timers.ElapsedEventArgs e) { RenderNextFrame(); } static double currentOATime = 0; List tempData = new List(); private void RenderNextFrame() { Stopwatch stopwatch = Stopwatch.StartNew(); string minName = string.Empty; if (_lChartAll == null) { return; } List datasStr = new List(); //计算数据中最小时间 if (currentOATime == 0) { double minTime = DateTime.Now.AddHours(1).ToOADate(); string name = string.Empty; foreach (var item in subNameList) { List dataDouList = new List(); using (RedisListService service = new RedisListService()) { var data = service.Get(item.Key, 0, 0).FirstOrDefault(); if (data != null) { datasStr = data.Split(',').Select(a => Convert.ToDouble(a)).ToList(); double oaTime = datasStr.First(); if (oaTime < minTime) { minTime = oaTime; currentOATime = oaTime; name=item.Key; } } } } if (currentOATime == 0) return; Debug.WriteLine("currentTimeFirst:{0},now:{1},sid:{2},count:{3}", DateTime.FromOADate(currentOATime),DateTime.Now, name, datasStr.Count); } else { //更新图表数据时间,每秒刷新一次 currentOATime = DateTime.FromOADate(currentOATime).AddSeconds(1).ToOADate(); } foreach (var item in subNameList) { using (RedisListService service = new RedisListService()) { var data = service.Get(item.Key, 0, 0).FirstOrDefault(); if (data != null) { datasStr = data.Split(',').Select(a => Convert.ToDouble(a)).ToList(); DateTime firstTime = DateTime.FromOADate(datasStr.First()); DateTime currentTime = DateTime.FromOADate(currentOATime); datasStr.RemoveAt(0); if (Math.Abs((currentTime - firstTime).TotalSeconds) < 1 && firstTime.Second == currentTime.Second) { service.RemoveStartFromList(item.Key); _data[item.Value.Index] = datasStr.ToArray(); } else if ((currentTime - firstTime).TotalSeconds < 0) { _data[item.Value.Index] = new double[datasStr.Count]; } else if ((currentTime - firstTime).TotalSeconds > 0) { firstTime.AddMilliseconds(-firstTime.Millisecond); //出更数据需要重新绘图表点 _data[item.Value.Index] = new double[datasStr.Count]; int offset = (int)(currentTime - firstTime).TotalSeconds; while (offset > 0) { service.RemoveStartFromList(item.Key); tempData.Add(item.Key+ firstTime); if (offset < 60) { // 不能超过缓存数, 更新数据 var time = currentTime.AddSeconds(-offset); int iCount= item.Value.datas.Count; if (iCount - offset > 0) { item.Value.datas[iCount - offset] = datasStr.ToArray(); } } data = service.Get(item.Key, 0, 0).FirstOrDefault(); if (data == null) break; datasStr = data.Split(',').Select(a => Convert.ToDouble(a)).ToList(); firstTime = DateTime.FromOADate(datasStr.First()); offset = (int)(currentTime - firstTime).TotalSeconds; datasStr.RemoveAt(0); Debug.WriteLine("timeMinData:{0},Time1:{1},sid:{2},offset:{3}", currentTime, firstTime, item.Key, offset); } } else { throw new Exception($"数据解析异常:{item.Key},{currentTime},{firstTime}"); } } else { _data[item.Value.Index] = new double[500]; } } item.Value.AddData(currentOATime, _data[item.Value.Index]); } stopwatch.Stop(); double time1 = stopwatch.ElapsedMilliseconds; stopwatch.Start(); bool isRefresh = false; //有新数据开始刷新 if (tempData.Count > 5) { DateTime startTime = DateTime.Today; foreach (var item in subNameList) { List temDou = new List(); var number = item.Value.datas.Count; for (int i = 0; i < number; i++) { temDou.AddRange(item.Value.datas[i]); } _data[item.Value.Index] = temDou.ToArray(); if (startTime == DateTime.Today) { startTime = DateTime.FromOADate(item.Value.StartOATime).AddSeconds(-item.Value.datas.Count); } } _lChartAll.ViewXY.XAxes[0].SetRange(_lChartAll.ViewXY.XAxes[0].DateTimeToAxisValue(startTime), _lChartAll.ViewXY.XAxes[0].DateTimeToAxisValue(startTime.AddSeconds(30))); LChartALL.ViewXY.DropOldSeriesData = true; _pointsAppended = LChartALL.ViewXY.XAxes[0].Minimum; isRefresh = true; tempData.Clear(); } _dispatcher.Invoke(() => { FeedData(isRefresh /*chartTitleText*/); }); stopwatch.Stop(); double time2 = stopwatch.ElapsedMilliseconds; Debug.WriteLine("timeFrame:{0},time1:{1},time1:{2}", DateTime.FromOADate(currentOATime), time1, time2); } double _pointsAppended = 0; double[][] _data; private void FeedData(bool isRefresh) { if (_lChartAll == null) return; _lChartAll.BeginUpdate(); if (isRefresh) { for (int seriesIndex = 0; seriesIndex < _channelCount; seriesIndex++) { _lChartAll.ViewXY.SampleDataSeries[seriesIndex].Clear(); } //foreach (var item in subNameList.Values) //{ // startTime = DateTime.FromOADate(item.StartOATime).AddSeconds(item.datas.Count); // _lChartAll.ViewXY.XAxes[0].SetRange(_lChartAll.ViewXY.XAxes[0].DateTimeToAxisValue(startTime), // _lChartAll.ViewXY.XAxes[0].DateTimeToAxisValue(startTime.AddSeconds(60))); // LChartALL.ViewXY.DropOldSeriesData = true; // _pointsAppended = LChartALL.ViewXY.XAxes[0].Minimum; // var number = item.datas.Count; // for (int i = 0; i < number; i++) // { // foreach (var d in subNameList) // { // double[] thisSeriesData = subNameList[d.Key].datas[i]; // _lChartAll.ViewXY.SampleDataSeries[d.Value.Index].AddSamples(thisSeriesData, false); // } // _pointsAppended += 1; // //Set X axis real-time scrolling position // double last = _pointsAppended; // _lChartAll.ViewXY.XAxes[0].ScrollPosition = last; // } // break; //} } //Append data to series for (int seriesIndex = 0; seriesIndex < _channelCount; seriesIndex++) { double[] thisSeriesData = _data[seriesIndex]; _lChartAll.ViewXY.SampleDataSeries[seriesIndex].AddSamples(thisSeriesData, false); _data[seriesIndex] = null; // System.Diagnostics.Debug.WriteLine("***********index:{0}, pointCount:{1},time:{2}", seriesIndex, // _lChartAll.ViewXY.SampleDataSeries[seriesIndex].PointCount, DateTime.Now); } _pointsAppended += 1; //Set X axis real-time scrolling position double lastX = _pointsAppended; _lChartAll.ViewXY.XAxes[0].ScrollPosition = lastX; //Update sweep bands if (_lChartAll.ViewXY.XAxes[0].ScrollMode == XAxisScrollMode.Sweeping) { //Dark band of old page fading away double pageLen = _lChartAll.ViewXY.XAxes[0].Maximum - _lChartAll.ViewXY.XAxes[0].Minimum; double sweepGapWidth = pageLen / 20.0; _lChartAll.ViewXY.Bands[0].SetValues(lastX - pageLen, lastX - pageLen + sweepGapWidth); if (_lChartAll.ViewXY.Bands[0].Visible == false) { _lChartAll.ViewXY.Bands[0].Visible = true; } //Bright new page band _lChartAll.ViewXY.Bands[1].SetValues(lastX - sweepGapWidth / 6, lastX); if (_lChartAll.ViewXY.Bands[1].Visible == false) { _lChartAll.ViewXY.Bands[1].Visible = true; } } else { //Hide sweeping bands if not in sweeping mode //if (_lChartAll.ViewXY.Bands[0].Visible == true) //{ // _lChartAll.ViewXY.Bands[0].Visible = false; //} //if (_lChartAll.ViewXY.Bands[1].Visible == true) //{ // _lChartAll.ViewXY.Bands[1].Visible = false; //} } _lChartAll.EndUpdate(); } public void OnNavigatedTo(NavigationContext navigationContext) { var str= navigationContext.Parameters.GetValue("model"); if(str == "实时波形") { IsRealtimeData = true; } else { IsRealtimeData = false; } } public bool IsNavigationTarget(NavigationContext navigationContext) { return true; } public void OnNavigatedFrom(NavigationContext navigationContext) { } #endregion } }