| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843 | using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.Data;using System.Diagnostics;using System.Globalization;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Forms;using Aitex.Core.RT.Log;using Aitex.Sorter.Common;using MECF.Framework.Common.DataCenter;using MECF.Framework.Common.Equipment;using MECF.Framework.UI.Client.CenterViews.DataLogs.Event;using MECF.Framework.UI.Client.CenterViews.DataLogs.ProcessHistory;#if !EXPORT_TO_CSVusing MECF.Framework.Common.Utilities;#endifusing MECF.Framework.UI.Client.CenterViews.Operations.RealTime;using MECF.Framework.UI.Client.ClientBase;using MECF.Framework.UI.Client.ClientBase.Charting;using MECF.Framework.UI.Client.ClientBase.EventArgs;using MECF.Framework.UI.Client.ClientBase.Pipelines;using MECF.Framework.UI.Client.ClientBase.Tree;using SciChart.Charting.Model.DataSeries;using SciChart.Charting.Visuals.Axes;using SciChart.Charting.Visuals.RenderableSeries;using SciChart.Core.Extensions;using SciChart.Core.Framework;using SciChart.Data.Model;using Cali = Caliburn.Micro;using DataGridCell = System.Windows.Controls.DataGridCell;using DateRange = SciChart.Data.Model.DateRange;using MessageBox = System.Windows.MessageBox;using TreeNode = MECF.Framework.UI.Client.ClientBase.Tree.TreeNode;namespace MECF.Framework.UI.Client.CenterViews.DataLogs.DataHistory{    public class DataViewModel : BusyIndicateableUiViewModelBase    {        #region Variables        /// <summary>        /// 一次最多查询的项目数。        /// </summary>        private const int MAX_ITEMS_PER_QUERY = 50;        private IRange _timeRange;        private IRange _visibleRangeValue;        private AutoRange _autoRange;        private CancellationTokenSource _cancellationTokenSource;        /// <summary>        /// 更新报告导出信息。        /// </summary>        private readonly IProgress<ProgressUpdatingEventArgs> _progCsvExport;        /// <summary>        /// 查询进度信息更新。        /// </summary>        private IProgress<ProgressUpdatingEventArgs> _progQueryUpdate;        /// <summary>        /// 挂起或恢复Chart更新        /// </summary>        private readonly IProgress<bool> _progChartSuspendUpdating;        private IUpdateSuspender _suspender;        /// <summary>        /// 打开错误消息对话框。        /// </summary>        private readonly IProgress<string> _progShowErrorMessageBox;        #endregion        #region Constructors        public DataViewModel()        {            DisplayName = "Data History";            SelectedData = new ChartingLineSeriesCollection(DisplayName);            var now = DateTime.Today;            SearchBeginTime = DateTime.Now.AddHours(-1); // -new TimeSpan(1, 0, 0, 0);            SearchEndTime = DateTime.Now;            //SearchBeginTime = new DateTime(now.Year, now.Month, now.Day, 00, 00, 00); ;// -new TimeSpan(1, 0, 0, 0);            //SearchEndTime = new DateTime(now.Year, now.Month, now.Day, 23, 59, 59);            var provider = new RealtimeProvider();            ParameterNodes = new TreeNode(DisplayName)            {                MaxTerminalSelectionAllowed = MAX_ITEMS_PER_QUERY            };            ParameterNodes.ChildNodes.AddRange(provider.GetTreeNodeParameters());            VisibleRangeTime = new DateRange(DateTime.Now.AddMinutes(-60), DateTime.Now.AddMinutes(60));            VisibleRangeValue = new DoubleRange(0, 10);            _progQueryUpdate = new Progress<ProgressUpdatingEventArgs>(e =>            {                if (e.CurrentProgress == e.TotalProgress)                {                    IsBusy = false;                    if (_cancellationTokenSource?.Token.IsCancellationRequested == false)                    {                        foreach (var renderableSeries in SelectedData)                        {                            var series = renderableSeries as FastLineSeries;                            var dataSeries = series?.GetDataSeries();                            try                            {                                if (series != null && dataSeries != null)                                {                                    var node = series.BackendParameterNode;                                    if (double.IsInfinity((double)dataSeries.YRange.Diff))                                    {                                        node.ClearStatistic();                                    }                                    else                                    {                                        var min = ((double)dataSeries.YMin);                                        var max = ((double)dataSeries.YMax);                                        var average =                                            dataSeries.Metadata.Cast<ParameterNodePoint>().Average(x => x.Value);                                        node.SetStatistic(min, max, average);                                    }                                }                            }                            catch (Exception ex)                            {                                var err = $"It's failed to load data of {series?.DataName ?? "Unknown"}, {ex.Message}";                                LOG.Error(err, ex);                            }                        }                    }                    ChartAutoRange = AutoRange.Never;                    ((DataView)View).chart.ZoomExtents();                }                BusyIndicatorContent = e.Message;            });            _progCsvExport = new Progress<ProgressUpdatingEventArgs>(e =>            {                BusyIndicatorContent = e.Message;            });            _progChartSuspendUpdating = new Progress<bool>(isSuspend =>            {                if (isSuspend)                    _suspender = ((DataView)View).chart.SuspendSuspendUpdates();                else                {                    try                    {                        if (_suspender?.IsSuspended == true)                            _suspender?.SafeDispose();                    }                    catch (Exception)                    {                        // 查询过程最后会强制恢复挂起一次,可能引发异常,忽略此异常。                    }                }            });            _progShowErrorMessageBox = new Progress<string>((error =>            {                System.Windows.Forms.MessageBox.Show(error, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);            }));        }        #endregion        #region Property        public bool IsPermission => Permission == 3;        private DataView view;        public TreeNode ParameterNodes { get; }        public ChartingLineSeriesCollection SelectedData { get; set; }        public AutoRange ChartAutoRange        {            get => _autoRange;            set            {                _autoRange = value;                NotifyOfPropertyChange(nameof(ChartAutoRange));            }        }        public IRange VisibleRangeTime        {            get => _timeRange;            set            {                _timeRange = value;                NotifyOfPropertyChange(nameof(VisibleRangeTime));            }        }        public IRange VisibleRangeValue        {            get => _visibleRangeValue;            set            {                _visibleRangeValue = value;                NotifyOfPropertyChange(nameof(VisibleRangeValue));            }        }        //public DateTime StartDateTime        //{        //    get => ((DataView)View).wfTimeFrom.Value;        //    set        //    {        //        ((DataView)View).wfTimeFrom.Value = value;        //        NotifyOfPropertyChange(nameof(StartDateTime));        //    }        //}        //public DateTime EndDateTime        //{        //    get => ((DataView)View).wfTimeTo.Value;        //    set        //    {        //        ((DataView)View).wfTimeTo.Value = value;        //        NotifyOfPropertyChange(nameof(EndDateTime));        //    }        //}        public DateTime SearchBeginTime { get; set; }        public DateTime SearchEndTime { get; set; }        #endregion        #region Methods        protected override void OnViewLoaded(object view)        {            base.OnViewLoaded(view);            this.view = (DataView)view;            //StartDateTime = DateTime.Now.Date;            //EndDateTime = DateTime.Now.Date.AddDays(1).AddTicks(-1);            this.view.wfTimeFrom.Content = SearchBeginTime.ToString("yyyy-MM-dd HH:mm:ss");            this.view.wfTimeTo.Content = SearchEndTime.ToString("yyyy-MM-dd HH:mm:ss");        }        public void SelectDate(string SelectType)        {            var windowManager = Caliburn.Micro.Core.IoC.Get<Caliburn.Micro.IWindowManager>();            if (SelectType == "Start")            {                this.SearchBeginTime = Convert.ToDateTime(this.view.wfTimeFrom.Content);                SelectDateViewModel selectdateViewModel = new SelectDateViewModel(SearchBeginTime);                var result = (windowManager as Caliburn.Micro.WindowManager)?.ShowDialogWithTitle(selectdateViewModel, null, "Start Time");                if (result == true)                {                    SearchBeginTime = selectdateViewModel.SearchDate;                    this.view.wfTimeFrom.Content = selectdateViewModel.SearchDate;                }            }            else            {                this.SearchEndTime = Convert.ToDateTime(this.view.wfTimeTo.Content);                SelectDateViewModel selectdateViewModel = new SelectDateViewModel(SearchEndTime);                var result = (windowManager as Caliburn.Micro.WindowManager)?.ShowDialogWithTitle(selectdateViewModel, null, "End Time");                if (result == true)                {                    this.view.wfTimeTo.Content = selectdateViewModel.SearchDate;                }              }        }        public void ToLeftClick()        {            var view = GetView() as DataView;            view.chart.sciChart.ChartModifier.XAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMin);        }        public void ToRightClick()        {            var view = GetView() as DataView;            view.chart.sciChart.ChartModifier.XAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMax);        }        public void ZoomInClick()        {            var view = GetView() as DataView;            view.chart.sciChart.ChartModifier.XAxis.ZoomBy(-0.1, -0.1);            view.chart.sciChart.ChartModifier.YAxis.ZoomBy(-0.1, -0.1);        }        public void ZoomOutClick()        {            var view = GetView() as DataView;            view.chart.sciChart.ChartModifier.XAxis.ZoomBy(0.1, 0.1);            view.chart.sciChart.ChartModifier.YAxis.ZoomBy(0.1, 0.1);        }        public void ToMoveUpClick()        {            var view = GetView() as DataView;            view.chart.sciChart.ChartModifier.YAxis.Scroll(-50, SciChart.Charting.ClipMode.ClipAtMin);        }        public void ToMoveDownClick()        {            var view = GetView() as DataView;            view.chart.sciChart.ChartModifier.YAxis.Scroll(50, SciChart.Charting.ClipMode.ClipAtMax);        }        public void Query(object parameter)        {            WaferHistoryRecipe waferHistoryRecipe = parameter as WaferHistoryRecipe;            if (waferHistoryRecipe != null)            {                System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>                {                    if (waferHistoryRecipe.StartTime != DateTime.MinValue)                        SearchBeginTime = waferHistoryRecipe.StartTime;                    if (waferHistoryRecipe.EndTime != DateTime.MinValue)                        SearchEndTime = waferHistoryRecipe.EndTime;                    else                        SearchEndTime = waferHistoryRecipe.StartTime.AddHours(1);                    //ParameterNodes.ForEachDo((x) =>                    //{                    //    x.Selected = true;                    //    ParameterCheck(x);                    //});                    QueryData();                }));            }        }        /// <summary>        /// 查询数据。        /// </summary>        /// <exception cref="Exception"></exception>        public void QueryData(bool isAppend = false)        {            this.SearchBeginTime = Convert.ToDateTime(this.view.wfTimeFrom.Content);            this.SearchEndTime = Convert.ToDateTime(this.view.wfTimeTo.Content);            if (SearchBeginTime > SearchEndTime)            {                MessageBox.Show("time range invalid, start time should be early than end time.", "Error",                    MessageBoxButton.OK,                    MessageBoxImage.Error);                return;            }            // 哪些模组(TreeView的顶层Nodes)有选中项。            var selectedModules = ParameterNodes.ChildNodes.Where(x => x.HasTerminalSelected).ToList();            if (!selectedModules.Any())            {                MessageBox.Show($"No item(s) are selected to query.", "Warning", MessageBoxButton.OK,                    MessageBoxImage.Warning);                return;            }            VisibleRangeTime = new DateRange(SearchBeginTime.AddHours(-1), SearchEndTime.AddHours(1));            ChartAutoRange = AutoRange.Always;            BusyIndicatorContent = "Preparing list ...";            IsBusy = true;            _cancellationTokenSource = new CancellationTokenSource();            #region 生成曲线列表            var selectedTerminal =                selectedModules.SelectMany(x => x.Flatten(true).Where(p => p.IsSelected == true)).ToList();            List<IRenderableSeries> appendedSeries = null;            if (isAppend)                appendedSeries = SelectedData.Append(selectedTerminal);            else            {                SelectedData.ReArrange(selectedTerminal);                appendedSeries = SelectedData.ToList();            }            SelectedData.ResetColors();            #endregion            var dataSeriesList = appendedSeries.Select(x => x.DataSeries).ToList();            Task.Run(async () =>            {                // 延时启动,等待UI准备好                await Task.Delay(500);                var pipeline = new TwoStagePipelineBasedTaskExecutor<DataSet, object>();                pipeline.Stage2ActionStarted += (s, e) =>                {                    // 挂起Chart                    _progChartSuspendUpdating.Report(true);                };                pipeline.Stage2ActionFinished += (s, e) =>                {                    // 挂起刷新                    _progChartSuspendUpdating.Report(false);                };                pipeline.Stage1Finished += (s, e) =>                {                    // 查询完毕,Chart可能仍在渲染。                    _progQueryUpdate?.Report(new ProgressUpdatingEventArgs(50, 100, "Still rendering chart ..."));                };                using (pipeline)                {                    var plTasks = pipeline.Start(null);                    try                    {                        //! 按时间分段查询,解决查询速度慢导致卡后台业务的问题。                        var ts = SearchEndTime - SearchBeginTime;                        if (ts.Days <= 1)                        {                            Query(pipeline, selectedModules, dataSeriesList, view.dataGrid1, SearchBeginTime, SearchEndTime,                                _cancellationTokenSource, _progQueryUpdate);                            // 结束流水线                            pipeline.AppendFunc1(null);                            pipeline.AppendFunc2(null);                        }                        else                        {                            var daySlices =                                DateRangeHelper.SplitInToHours(new DateRangeHelper(SearchBeginTime, SearchEndTime), 12);                            foreach (var range in daySlices)                            {                                Query(pipeline, selectedModules, dataSeriesList, view.dataGrid1, range.Start, range.End,                                    _cancellationTokenSource, _progQueryUpdate);                                if (_cancellationTokenSource.Token.IsCancellationRequested)                                    break;                                await Task.Delay(1);                            }                            // 结束流水线                            pipeline.AppendFunc1(null);                            pipeline.AppendFunc2(null);                        }                        await Task.WhenAll(plTasks.ToArray());                    }                    catch (ThreadAbortException ex)                    {                        Thread.Sleep(500);                        // 查询操作被取消。                        Debug.WriteLine(ex);                    }                    catch (AggregateException ae)                    {                        var errs = new StringBuilder();                        foreach (var ex in ae.Flatten().InnerExceptions)                        {                            LOG.Error(ex.Message, ex);                            errs.AppendLine(ex.Message);                        }                        var errMsg = $"It's failed to query data, {errs}";                        _progShowErrorMessageBox.Report(errMsg);                        LOG.Error(errMsg, ae);                    }                    catch (Exception ex)                    {                        var errMsg = $"It's failed to query data, {ex.Message}";                        _progShowErrorMessageBox.Report(errMsg);                        LOG.Error(errMsg, ex);                    }                    finally                    {                        // 等待一下UI                        Thread.Sleep(100);                        _progQueryUpdate.Report(new ProgressUpdatingEventArgs(100, 100, ""));                        // 强制恢复Chart刷新,避免异常情况导致的Chart挂起。                        _progChartSuspendUpdating.Report(false);                    }                }            });        }        /// <summary>        /// 查询数据        /// </summary>        private static void Query(TwoStagePipelineBasedTaskExecutor<DataSet, object> pipeline, IEnumerable<TreeNode> selectedModules, List<IDataSeries> dataSeriesList, System.Windows.Controls.DataGrid dataGrid, DateTime startTime, DateTime endTime,            CancellationTokenSource cancellation, IProgress<ProgressUpdatingEventArgs> progressReporter = null)        {            pipeline.AppendFunc1(() =>                SearchDataBaseAsync(                    selectedModules,                    new DateRangeHelper(startTime, endTime),                    cancellation,                    progressReporter));            pipeline.AppendFunc2(ds =>            {                RenderChartAndTable(ds, dataSeriesList, dataGrid, cancellation, progressReporter);                return null;            });            //pipeline.AppendFunc2(ds =>            //{            //    RenderDataGridTable(ds, , cancellation, progressReporter);            //    return null;            //});        }        /// <summary>        /// 取消查询。        /// </summary>        public void CancelQuery()        {            Task.Run(() =>            {                if (_cancellationTokenSource?.Token.CanBeCanceled == true)                {                    _cancellationTokenSource.Cancel();                }                Thread.Sleep(100);                _progQueryUpdate.Report(new ProgressUpdatingEventArgs(100, 100, ""));                _progChartSuspendUpdating.Report(false);            });            if (View is DataView view)                view.dataGrid.CancelOperation();        }        /// <summary>        /// 检查指定的表名是否存在。        /// </summary>        /// <param name="tableName"></param>        /// <returns></returns>        private static bool CheckTableExists(string tableName)        {            var sql =                $"SELECT EXISTS ( SELECT FROM pg_tables WHERE schemaname = 'public' AND tablename = '{tableName}' );";            var table = QueryDataClient.Instance.Service.QueryData(sql);            if (table == null)                return false;            if (table.Rows.Count <= 0)                return false;            var value = table.Rows[0][0].ToString();            if (value.ToLower() == "true")                return true;            return false;        }        /// <summary>        /// 根据左侧选项查询数据        /// </summary>        /// <returns></returns>        private static DataSet SearchDataBaseAsync(            IEnumerable<TreeNode> modules, DateRangeHelper dateRange,            CancellationTokenSource cancellation = null,            IProgress<ProgressUpdatingEventArgs> progressReporter = null)        {            var ds = new DataSet();            using (cancellation?.Token.Register(Thread.CurrentThread.Abort, true))            {                // 遍历模组                foreach (var module in modules)                {                    var sql = new StringBuilder();                    //! 因为数据库中按天拆表,无法一次性查询数据,需使用UNION合并多表查询,因此此处按天拼接SQL表达式                    // 最终SQL表达式结构为:                    // (select xx from date1.xx) union (select xx from date2.xx) union (select xx from date3.xx)                    // where time between xxx and xxx                    // order by time asc                    var ts = dateRange.Diff;                    for (var day = 0; day <= ts.Days; day++)                    {                        // 检查表名是否存在,否则SQL执行出错。                        var tblName = $"{dateRange.Start.AddDays(day):yyyyMMdd}.{module}";                        if (module.ToString() == "IO")                        {                            //var node = module.ChildNodes.FirstOrDefault(x => (bool)x.HasTerminalSelected);                            tblName = $"{dateRange.Start.AddDays(day):yyyyMMdd}.System";                        }                        else                        if (!ModuleHelper.IsPm(module.ToString()))                        {                            tblName = $"{dateRange.Start.AddDays(day):yyyyMMdd}.System";                        }                        if (CheckTableExists(tblName))                        {                            sql.Append("select \"time\" AS InternalTimeStamp");                            var selectedParams = module.Flatten(true)                                .Where(x => x.IsSelected == true);                            // 添加待查询的列                            foreach (var item in selectedParams)                            {                                sql.Append("," + $"\"{item}\"");                            }                            sql.Append($" from \"{tblName}\" ");                            if (day < ts.Days)                                sql.Append(" UNION ");                        }                    }                    // 所有表名不可用,可能是日期范围错误                    if (sql.Length <= 0)                    {                        continue;                    }                    sql.Append(                        $" where \"time\" between {dateRange.Start.Ticks} and {dateRange.End.Ticks} order by InternalTimeStamp asc");                    progressReporter?.Report(new ProgressUpdatingEventArgs(20, 100,                        $"Querying {dateRange}..."));                    if (cancellation?.Token.IsCancellationRequested == true)                        return null;                    // 查询数据并将返回的结果存储在DataSet中                    var dataTable = QueryDataClient.Instance.Service.QueryData(sql.ToString());                    if (cancellation?.Token.IsCancellationRequested == true)                        return null;                    //! 返回的 DataTable 可能不存在,原因是上述代码自动生成的表明可能不存在。                    if (dataTable == null)                        continue;                    dataTable.TableName = module.Name;                    ds.Tables.Add(dataTable);                }            }            return ds;        }        /// <summary>        /// 渲染图表。        /// </summary>        /// <param name="ds"></param>        /// <param name="dataSeriesList"></param>        /// <param name="cancellation"></param>        /// <param name="progressReporter"></param>        /// <exception cref="Exception"></exception>        private static void RenderChartAndTable(            DataSet ds, List<IDataSeries> dataSeriesList, System.Windows.Controls.DataGrid dataGrid,            CancellationTokenSource cancellation = null,            IProgress<ProgressUpdatingEventArgs> progressReporter = null)        {            if (ds == null || ds.Tables.Count <= 0)                return;            Dictionary<string, Dictionary<long, string>> bigTable = new Dictionary<string, Dictionary<long, string>>();            System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>            {                dataGrid.Columns.Clear();                DataGridTextColumn dataGridTextColumn = new DataGridTextColumn();                dataGridTextColumn.Header = "Time";                dataGridTextColumn.Binding = new System.Windows.Data.Binding("internaltimestamp");                ((System.Windows.Data.Binding)dataGridTextColumn.Binding).Converter = new StringToDateTimeStringConvert();                dataGrid.Columns.Add(dataGridTextColumn);            }));            // 一个Table一个模组            foreach (var table in ds.Tables.Cast<DataTable>())            {                if (table.Rows.Count <= 0)                    continue;                // 一列对应模组中的某个数据记录点                foreach (var col in table.Columns.Cast<DataColumn>())                {                    // 忽略时间列                    if (col.Ordinal == 0)                        continue;                    Dictionary<long, string> dictColumn = new Dictionary<long, string>();                    var fullName = col.ColumnName;                    col.ColumnName = col.ColumnName.Replace(".", "");                    var dataSeries =                        dataSeriesList.FirstOrDefault(x => x.SeriesName == fullName) as XyDataSeries<DateTime, double>;                    if (dataSeries == null)                        continue;                    var rows = table.Rows;                    var dateList = new List<DateTime>();                    var valueList = new List<double>();                    var metaList = new List<ParameterNodePoint>();                    for (var i = 0; i < rows.Count; i++)                    {                        var date = new DateTime(long.Parse(rows[i][0].ToString()));                        var cellValue = rows[i][col];                        var value = double.NaN;                        if (cellValue is bool b)                            value = b ? 1 : 0;                        else if (double.TryParse(cellValue.ToString(), out var num))                            value = num;                        else                            value = 0;                        dateList.Add(date);                        valueList.Add(value);                        metaList.Add(new ParameterNodePoint(date, value));                        dictColumn.Add(long.Parse(rows[i][0].ToString()), value.ToString());                        if (cancellation?.Token.IsCancellationRequested == true)                            return;                    }                    bigTable.Add(fullName.Replace(".", ""), dictColumn);                    System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>                    {                        DataGridTextColumn dataGridTextColumn2 = new DataGridTextColumn();                        dataGridTextColumn2.Header = fullName;                        dataGridTextColumn2.Binding = new System.Windows.Data.Binding(fullName.Replace(".", ""));                        var MyStyle = new Style(typeof(DataGridCell))                        {                            Setters = {        new Setter(TextBlock.TextAlignmentProperty, TextAlignment.Center)    }                        };                        dataGridTextColumn2.CellStyle = MyStyle;                        dataGrid.Columns.Add(dataGridTextColumn2);                    }));                    if (cancellation?.Token.IsCancellationRequested == true)                        return;                    dataSeries.Append(dateList, valueList, metaList);                }                if (cancellation?.Token.IsCancellationRequested == true)                    return;                // 每一轮更新完毕后会恢复Chart刷新,                // 数据量太小时会频繁挂起和恢复Chart,导致Chart不刷新,需要稍等一下UI。                Thread.Sleep(50);            }            System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>            {                System.Data.DataTable dt = new System.Data.DataTable();                dt = new System.Data.DataTable($"Temp");                dt.Columns.Add("internaltimestamp", typeof(long));                foreach (var item in bigTable.Keys)                {                    dt.Columns.Add(item, typeof(string));                }                if (bigTable.Count > 0)                {                    foreach (var subitem in bigTable[bigTable.FirstOrDefault().Key].Keys)                    {                        var row = dt.NewRow();                        row[0] = subitem;                        foreach (var col in bigTable.Keys)                        {                            row[col] = bigTable[col][subitem];                        }                        dt.Rows.Add(row);                    }                }                dataGrid.ItemsSource = dt.DefaultView;            }));        }        public void Exporting(object sender, EventArgs e)        {            BusyIndicatorContent = "Exporting Start ...";            IsBusy = true;        }        public void Exported(object sender, EventArgs e)        {            IsBusy = false;        }        public void Deleted(object sender, EventArgs e)        {            ((DataView)View).tvParameterNodes.ClearPresetGroupSelectionOnly();        }        public void ProgressUpdating(object sender, ProgressUpdatingEventArgs e)        {            _progCsvExport.Report(e);        }        #endregion    }    public class StringToDateTimeStringConvert : IValueConverter    {        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)        {            return new DateTime((Int64)value).ToString("yyyy/MM/dd HH:mm:ss");        }        public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)        {            return null;        }    }}
 |