123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using Aitex.UI.Charting.Model;
- using System.Threading;
- using Abt.Controls.SciChart;
- using System.Windows.Media;
- using Aitex.UI.Charting.Command;
- using System.Windows.Input;
- using System.Collections.ObjectModel;
- using System.Windows.Threading;
- using System.Windows;
- using System.Windows.Controls;
- using Abt.Controls.SciChart.Model.DataSeries;
- using Abt.Controls.SciChart.Visuals.RenderableSeries;
- using System.ComponentModel;
- using Aitex.UI.Charting.View;
- using DataAnalysisControl.Core;
- namespace Aitex.UI.Charting.ViewModel
- {
- public sealed class CommonViewModel : ChartingBaseViewModel
- {
- /// <summary>
- /// 获取所有数据曲线对象
- /// </summary>
- public List<MyLineSeries> GetAllDataLineSeries()
- {
- List<MyLineSeries> lines = new List<MyLineSeries>();
- for (int i = 0; i < RenderableSeries.Count; i++)
- {
- var line = RenderableSeries[i] as MyLineSeries;
- if (line != null)
- {
- lines.Add(line);
- }
- }
- return lines;
- }
- /// <summary>
- /// new object is not allowed
- /// </summary>
- private CommonViewModel()
- {
- //主窗口的显示
- DataConfigViewVisibility = Visibility.Collapsed;
- DataDisplayViewVisibility = Visibility.Visible;
- Switch2DataCfgViewCommand = new ChartingCommand((o) => true, (o) =>
- {
- DataDisplayViewVisibility = Visibility.Collapsed;
- DataConfigViewVisibility = Visibility.Visible;
- InvokePropertyChanged("DataDisplayViewVisibility");
- InvokePropertyChanged("DataConfigViewVisibility");
- });
- Switch2DataDisplayViewCommand = new ChartingCommand((o) => true, (o) =>
- {
- DataConfigViewVisibility = Visibility.Collapsed;
- DataDisplayViewVisibility = Visibility.Visible;
- InvokePropertyChanged("DataDisplayViewVisibility");
- InvokePropertyChanged("DataConfigViewVisibility");
- });
- RenderableSeries = new ObservableCollection<IRenderableSeries>();
- DataSources = new Dictionary<string, IDataSource>();
- //显示或隐藏数据配置窗口
- ToggleDataDisplayPanelCommand = new ChartingCommand((o) => true, (o) =>
- {
- if (DataConfigViewRow != null)
- {
- DataConfigViewRow.Height = new GridLength(DataConfigViewRow.Height.Value > 0 ? 0 : 150);
- InvokePropertyChanged("IsDataConfigVisiable");
- }
- });
- //Charting控件的某些元素必须STA,UI主线程完成,因此此处需定义个DispatcherTimer来实现某些GUI相关的操作
- _dispatcherTimer = new DispatcherTimer();
- _dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 100);
- _dispatcherTimer.Tick += new EventHandler(_dispatcherTimer_Tick);
- }
- public void Start()
- {
- if (_isAlive) return;
- _isAlive = true;
- System.Threading.Tasks.Task.Factory.StartNew(TaskRun);
- _dispatcherTimer.Start();
- }
- public void Stop()
- {
- _dispatcherTimer.Stop();
- _isAlive = false;
- }
- bool _isAlive = false;
- /// <summary>
- /// DispatcherTimer中定期处理一些和GUI相关的处理,例如新建、删除LineSeries对象等
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- void _dispatcherTimer_Tick(object sender, EventArgs e)
- {
- //执行命令队列中的指令
- if (_commandQueue.Count > 0)
- {
- if (!Monitor.TryEnter(_dataLocker))
- return;
- try
- {
- IEnumerable<ICommand> commandList = null;
- lock (_cmdQLocker)
- {
- commandList = _commandQueue.ToList();
- _commandQueue.Clear();
- }
- foreach (var command in commandList)
- {
- command.Execute(this);
- }
- }
- catch (Exception ex)
- {
- CONTEXT.WriteLog(ex);
- }
- finally
- {
- Monitor.Exit(_dataLocker);
- }
- }
- }
- DispatcherTimer _dispatcherTimer;
- //单实例定义
- private readonly static Lazy<CommonViewModel> _instance = new Lazy<CommonViewModel>(() => new CommonViewModel(), true);
- /// <summary>
- /// 获取当前对象的单实例
- /// </summary>
- public static CommonViewModel Instance
- {
- get
- {
- return _instance.Value;
- }
- }
- #region view switch
- public ICommand ToggleDataDisplayPanelCommand { get; set; }
- public Visibility DataConfigViewVisibility { get; private set; }
- public Visibility DataDisplayViewVisibility { get; private set; }
- public ICommand Switch2DataCfgViewCommand { get; set; }
- public ICommand Switch2DataDisplayViewCommand { get; set; }
- #endregion
- #region data source operations
- /// <summary>
- /// 生长率曲线相关的定义
- /// </summary>
- public MyLineSeries GrowthRateRenderableSeries { get; set; }
- public RowDefinition DataConfigViewRow { get; set; }
- public bool IsDataConfigVisiable { get { return DataConfigViewRow != null && DataConfigViewRow.Height.Value > 0; } }
- Queue<ICommand> _commandQueue = new Queue<ICommand>();
- object _cmdQLocker = new object();
- object _dataLocker = new object();
- public Dictionary<string, IDataSource> DataSources { get; set; }
- public ObservableCollection<IRenderableSeries> RenderableSeries { get; set; }
- public DateTime Time1 { get; set; } //时间标尺1
- public DateTime Time2 { get; set; } //时间标尺2
- IDataSource _currentSelectedDataSource;
- public IDataSource CurrentSelectedDataSource
- {
- get
- {
- return _currentSelectedDataSource;
- }
- set
- {
- if ((value != null) &&(_currentSelectedDataSource == null || _currentSelectedDataSource != value))
- {
- if (!string.IsNullOrEmpty(value.WaferDisplayIndex) &&
- (_currentSelectedDataSource == null ||
- !value.WaferDisplayIndex.Equals(_currentSelectedDataSource.WaferDisplayIndex)))
- {
- WaferDisplayIndex = value.WaferDisplayIndex;
- }
- else
- {
- WaferDisplayIndex = GetWaferDisplayIndex(value.BeginTime, value.ChamberName);
- }
- value.WaferDisplayIndex = WaferDisplayIndex;
- }
- _currentSelectedDataSource = value;
- if (_currentSelectedDataSource != null)
- CurrentSelectedDataSourceName = _currentSelectedDataSource.Title;
- InvokePropertyChanged("CurrentSelectedDataSource");
- InvokePropertyChanged("CurrentSelectedDataSourceName");
- }
- }
- /// <summary>
- /// 获取数据曲线对象
- /// </summary>
- /// <param name="uniqueDataId"></param>
- /// <returns></returns>
- public MyLineSeries GetDataLineSeries(string uniqueDataId)
- {
- for (int i = 0; i < RenderableSeries.Count; i++)
- {
- var line = RenderableSeries[i] as MyLineSeries;
- if (line != null && line.UniqueId == uniqueDataId)
- {
- return RenderableSeries[i] as MyLineSeries;
- }
- }
- return null;
- }
- public string CurrentSelectedDataSourceName
- {
- get;
- private set;
- }
- public ObservableCollection<IDataSource> DataSourceList
- {
- get
- {
- var ret = new ObservableCollection<IDataSource>();
- foreach (var key in DataSources.Keys)
- ret.Add(DataSources[key]);
- return ret;
- }
- }
- public List<string> DataSourceNameList
- {
- get
- {
- return DataSources.Keys.ToList();
- }
- }
- /// <summary>
- /// 移除先前绘制的生长率计算曲线
- /// </summary>
- public void ClearGrowthRateCurve()
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new RemoveGrowthCurveCommand());
- }
- }
- /// <summary>
- /// 新增DataSource对象
- /// </summary>
- /// <param name="dataSource"></param>
- /// <returns></returns>
- public void AddDataSource(IDataSource dataSource)
- {
- lock (_cmdQLocker)
- {
- CONTEXT.WriteLog("添加数据源");
- _commandQueue.Enqueue(new AddDataSourceCommand(dataSource));
- }
- }
- /// <summary>
- /// 移除DataSource对象
- /// </summary>
- /// <param name="sourceName">移除指定的数据源,如果sourceName为null,则移除所有的数据源</param>
- /// <returns></returns>
- public void RemoveDataSource(string sourceName)
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new RemoveDataSourceCommand(sourceName));
- }
- }
- #endregion
- #region data item operations
- /// <summary>
- /// 添加Data Item对象
- /// </summary>
- /// <param name="dataSourceName"></param>
- /// <param name="seriesName"></param>
- /// <param name="displayName"></param>
- /// <param name="lineColor"></param>
- /// <param name="factor"></param>
- /// <param name="offset"></param>
- /// <param name="lineWidth"></param>
- public void AddDataSeries(string dataSourceName, string seriesName, string displayName, Color lineColor, float factor, float offset, int lineWidth)
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new AddDataSeriesCommand(dataSourceName, seriesName, displayName, lineColor, factor, offset, lineWidth));
- }
- }
- /// <summary>
- /// 显示所有当前数据
- /// </summary>
- public void ShowAllSeries()
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new ShowAllSeriesCommand());
- }
- }
- /// <summary>
- /// 隐藏当前所有数据
- /// </summary>
- public void HidAllSeries()
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new HidAllSeriesCommand());
- }
- }
- /// <summary>
- /// 显示预设的数据管理对话框
- /// </summary>
- public void LoadPresetSetting()
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new LoadPresetSettingCommand());
- }
- }
- /// <summary>
- /// 数据源时间更新
- /// </summary>
- /// <param name="dataSourceName"></param>
- /// <param name="syncTimePoint"></param>
- /// <param name="syncStepName"></param>
- public void SyncSourceTime(string dataSourceName, DateTime syncTimePoint, string syncStepName)
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new SourceTimeSyncCommand(dataSourceName, syncTimePoint, syncStepName));
- }
- }
- /// <summary>
- /// 数据缩放因子+Offset改变命令
- /// </summary>
- /// <param name="uniqueDataName"></param>
- /// <param name="newFactor"></param>
- public void ChangeDataDisplayFactor(string uniqueDataName, double newFactor, double newOffset)
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new ChangeFactorOffsetCommand(uniqueDataName, newFactor, newOffset));
- }
- }
- /// <summary>
- /// 去除DataItem对象
- /// </summary>
- /// <param name="uniqueDataId"></param>
- public void RemoveDataSeries(string uniqueDataId)
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new RemoveDataSeriesCommand(uniqueDataId));
- }
- }
- /// <summary>
- /// 保存当前所有数据
- /// </summary>
- public void ExportAllSeries()
- {
- lock (_cmdQLocker)
- {
- _commandQueue.Enqueue(new ExportAllSeriesCommand());
- }
- }
- #endregion
- private int GetIndex(List<string> Total, int index)
- {
- int _result = -1;
- //string[] _temp = Total.Split(',');
- //for (int i = 0; i < _temp.Length; i++)
- //{
- // if (_temp[i].PadLeft(2,'0').Equals(index.ToString().Trim().PadLeft(2,'0')))
- // {
- // _result = i+1;
- // break;
- // }
- //}
- _result = Total.FindIndex((x) => x == (index.ToString().Trim().PadLeft(2, '0')));
- if (_result >= 0) { _result++; }
- return _result;
- }
- #region thread - timely retrieve data
- /// <summary>
- /// data getting task
- /// </summary>
- void TaskRun()
- {
- while (_isAlive)
- {
- Thread.Sleep(100);
- try
- {
- //为提升效率,将线程从IDataSource对象获取数据的缓慢过程尽量和Chart对象通过UI线程的更新分开进行
- //通过Dictionary将数据进行当前线程内的暂时缓存
- List<Tuple<string/*data Id*/, DataItem/*data item*/, DateTime/*end time*/>> newDataDic =
- new List<Tuple<string, DataItem, DateTime>>();
- Dictionary<IDataSource, List<Tuple<IDataSource, string/*dataName*/, string/*dataId*/, DateTime/*beginTime*/, DateTime/*endTime*/>>> rqDataDic =
- new Dictionary<IDataSource, List<Tuple<IDataSource, string, string, DateTime, DateTime>>>();
- lock (_dataLocker)
- {
- foreach(MyLineSeries line in RenderableSeries)
- {
- if (DateTime.Now < line.NextQueryTime || line == null || line.DataSource == null)
- continue;
- IDataSource dataSource = line.DataSource; //数据源对象
- string chamName = dataSource.ChamberName; //Chamber名称
- DateTime lastUpdateTime = line.LastUpdateTime; //最后一次获取数据的时间
- DateTime dataEndTime = dataSource.EndTime; //数据源的结束时间
- if (lastUpdateTime >= dataEndTime)
- continue;
- DateTime nextDataTime = lastUpdateTime.Date + new TimeSpan(0, 23, 59, 59, 999); //ChartDataDic[dataId].Item4.LastUpdateTime + new TimeSpan(2, 0, 0);
- if (nextDataTime > dataEndTime) nextDataTime = dataEndTime;
- string dataName = line.SeriesName;
-
- //if(int.TryParse(WaferDisplayIndex.Split(',')[index-1],out index))
- if (!rqDataDic.ContainsKey(dataSource))
- rqDataDic.Add(dataSource, new List<Tuple<IDataSource, string, string, DateTime, DateTime>>());
- rqDataDic[dataSource].Add(new Tuple<IDataSource, string, string, DateTime, DateTime>(dataSource, dataName, line.UniqueId, lastUpdateTime, nextDataTime));
- }
- }
- //优化1:在此作判断,如果多个DataItem的如果在同一个DataSource中而且beginTime,EndTime完全一致,那么合并后进行Select Query可以进行加速
- foreach (var ds in rqDataDic.Keys)
- {
- var tempDic = new Dictionary<string, List<Tuple<IDataSource, string/*dataName*/, string/*dataId*/, DateTime/*beginTime*/, DateTime/*endTime*/>>>();
- foreach (var daq in rqDataDic[ds])
- {
- string id = string.Format("{0}-{1}", daq.Item4.Ticks, daq.Item5.Ticks);
- if (!tempDic.ContainsKey(id))
- tempDic.Add(id, new List<Tuple<IDataSource,string,string,DateTime,DateTime>>());
- tempDic[id].Add(daq);
- }
-
- //优化2:如果存在2组不同时间区间的数据请求,那么优化执行时间较早的数据请求,目的为了将多组不同时间段的请求合并为一个SQL语句,提升SQL查询效率
- DateTime earliestEndT = DateTime.MaxValue;
- foreach (var tickKey in tempDic.Keys)
- {
- var endT = tempDic[tickKey][0].Item5;
- if (endT < earliestEndT)
- earliestEndT = endT;
- }
- List<string>removeQueryList = new List<string>();
- foreach (var tickKey in tempDic.Keys)
- {
- var beginT = tempDic[tickKey][0].Item4;
- if (beginT > earliestEndT)
- removeQueryList.Add(tickKey);
- }
- foreach (var tickKey in removeQueryList)
- tempDic.Remove(tickKey);
- //database query
- foreach (var tickKey in tempDic.Keys)
- {
- List<string> dataNameList = new List<string>();
- List<string> dataIdList = new List<string>();
- foreach (var da in tempDic[tickKey])
- {
- dataNameList.Add(da.Item2);
- dataIdList.Add(da.Item3);
- }
- if (tempDic[tickKey].Count > 0)
- {
- List<DataItem> rtdata;
- var singleData = tempDic[tickKey][0];
- var dataSource = singleData.Item1;
- var beginT = singleData.Item4;
- var endT = singleData.Item5;
- var isSucc = dataSource.GetData(dataNameList, beginT, endT, out rtdata);
- if (isSucc)
- {
- for (int ss = 0; ss < dataIdList.Count; ss++)
- {
- newDataDic.Add(new Tuple<string, DataItem, DateTime>(dataIdList[ss], rtdata[ss], endT));
- }
- }
- }
- }
- }
- //对Chart对象的数据集进行集中更新
- Application.Current.Dispatcher.Invoke(new Action<List<Tuple<string/*data Id*/, DataItem/*data item*/, DateTime/*end time*/>>>((o) =>
- {
- if (o.Count > 0)
- {
- lock (_dataLocker)
- {
- var nextRetryQueryTime = DateTime.Now + new TimeSpan(0, 0, 0, 2);
- foreach (var item in o)
- {
- var dataId = item.Item1;
- var dataName = item.Item2.DataName;
- var line = GetDataLineSeries(dataId);
- if (line == null)
- continue;
- if (item.Item2.TimeStamp.Count == 0) //get nothing for this querying
- {
- if (item.Item3.Date >= DateTime.Now.Date)//possible data is still in generating today, try again 2 seconds later
- {
- line.NextQueryTime = nextRetryQueryTime;
- }
- else //data not available for this day, jump to query next day
- {
- line.NextQueryTime = DateTime.Now;
- line.LastUpdateTime = item.Item3.Date + new TimeSpan(1, 0, 0, 0);
- }
- }
- else //get something for this querying
- {
- //update next query time point
- line.NextQueryTime = DateTime.Now;
- if (item.Item3.Date >= DateTime.Now.Date) //update the last update time by exactly last data timestamp, for some more data is in generating state
- line.LastUpdateTime = item.Item2.TimeStamp[item.Item2.TimeStamp.Count - 1] + new TimeSpan(0, 0, 0, 0, 500);
- else
- line.LastUpdateTime = item.Item3.Date + new TimeSpan(1, 0, 0, 0);
- //write to data buf
- line.DataSource.Datas[dataName].RawData.AddRange(item.Item2.RawData);
- line.DataSource.Datas[dataName].TimeStamp.AddRange(item.Item2.TimeStamp);
- var timeMove = line.DataSource.TimeMove;
- var factorScale = (float)line.Factor;
- var offset = (float)line.Offset;
- var dataSet = line.DataSeries as DataSeries<DateTime, float>;
- if (timeMove.Ticks != 0 && (factorScale == 1 && offset == 0))
- {
- List<DateTime> movedTimeList = new List<DateTime>();
- foreach (var time1 in item.Item2.TimeStamp)
- {
- movedTimeList.Add(time1 + timeMove);
- }
- dataSet.Append(movedTimeList, item.Item2.RawData);
- }
- else if (timeMove.Ticks == 0 && (factorScale != 1 || offset != 0))
- {
- List<float> scaledValue = new List<float>();
- foreach (var value1 in item.Item2.RawData)
- {
- scaledValue.Add(value1 * factorScale + offset);
- }
- dataSet.Append(item.Item2.TimeStamp, scaledValue);
- }
- else if (timeMove.Ticks != 0 && (factorScale != 1|| offset != 0))
- {
- List<DateTime> movedTimeList = new List<DateTime>();
- List<float> scaledValue = new List<float>();
- foreach (var time1 in item.Item2.TimeStamp)
- {
- movedTimeList.Add(time1 + timeMove);
- }
- foreach (var value1 in item.Item2.RawData)
- {
- scaledValue.Add(value1 * factorScale + offset);
- }
- dataSet.Append(movedTimeList, scaledValue);
- }
- else
- {
- dataSet.Append(item.Item2.TimeStamp, item.Item2.RawData);
- }
- }
- }
- }
- InvokePropertyChanged("RenderableSeries");
- }
- }), newDataDic);
- }
- catch (Exception ex)
- {
- CONTEXT.WriteLog(ex, "Charting绘图Task运行发生异常");
- }
- }
- }
- #endregion
- }
- }
|