/// <summary>
        /// MainWindow NewData, option to force update all
        /// </summary>
        /// <param name="updateall">force update all flag</param>
        public void NewData(bool updateall = false)
        {
            App.Current?.Dispatcher.Invoke((Action) delegate // invoke in GUI thread
            {
                double[] currentprint = DBuilder.Current.Print;
                CSChartVM.NewData(currentprint, updateall);
                if (DBuilder.OHLC[0].RowsChanged == 0)
                {
                    // notify label formatter change
                    CSLabelFormatter = CSChartVM.XAxisLabelFormatter;
                    NotifyPropertyChanged("CSLabelFormatter");
                }

                VolumeChartVM.NewData(updateall);
                BidVDChartVM.NewData(updateall);
                AskVDChartVM.NewData(updateall);
                TradedVDChartVM.NewData(updateall);
                PriceRDChartVM.NewData(updateall);
                VolumeTDChartVM.NewData(updateall);
                BATVDistYAxisUpdate();

                QuotesTextVM.NewData();
                VWAPTextVM.NewData();
            });
        }
        /// <summary>
        /// Selection button click command handler
        /// </summary>
        /// <param name="o">button event object</param>
        public void SelectSourceCommand(object o)
        {
            string srcname;
            int    dsidx;

            // event object should be a tuple created by ViewModelButtonsSelect, see ViewModelButtonsSelect.ButtonBindings.BtnParameters
            // try to convert event object to <string,int> tuple and assign srcname, and dsidx, else return
            try
            {
                Tuple <string, int> btnbinding = (Tuple <string, int>)o; // convert object back to tuple
                srcname = btnbinding.Item1;
                dsidx   = btnbinding.Item2;
            }
            catch
            {
                return;
            }


            // if not already assigned to dsidx, switch chart data source to dsidx using ViewModel ChangeDataSource()
            switch (srcname)
            {
            case "OHLCVolume":
                if (DBuilder.OHLC[dsidx].TSControl.TimeInterval != CSChartVM.DSOHLC.TSControl.TimeInterval)
                {
                    CSChartVM.ChangeDataSource(DBuilder.OHLC[dsidx], DBuilder.Current.Print);
                    VolumeChartVM.ChangeDataSource(DBuilder.Volume[dsidx]);

                    // notify label formatter change
                    CSLabelFormatter = CSChartVM.XAxisLabelFormatter;
                    NotifyPropertyChanged("CSLabelFormatter");
                }
                break;

            case "BATVDist":
                if (DBuilder.TFAnalytics.BidVolumeDist[dsidx].TSControl.TimeInterval !=
                    BidVDChartVM.DSValueDist.TSControl.TimeInterval)
                {
                    BidVDChartVM.ChangeDataSource(DBuilder.TFAnalytics.BidVolumeDist[dsidx]);
                    AskVDChartVM.ChangeDataSource(DBuilder.TFAnalytics.AskVolumeDist[dsidx]);
                    TradedVDChartVM.ChangeDataSource(DBuilder.TFAnalytics.TradedVolumeDist[dsidx]);
                }
                break;

            case "PriceRDist":
                if (DBuilder.TFAnalytics.PriceRangeDist[dsidx].TSControl.TimeInterval !=
                    PriceRDChartVM.DSValueDist.TSControl.TimeInterval)
                {
                    PriceRDChartVM.ChangeDataSource(DBuilder.TFAnalytics.PriceRangeDist[dsidx]);
                }
                break;

            case "VolumeTDist":
                if (DBuilder.TFAnalytics.VolumeTotalDist[dsidx].TSControl.TimeInterval !=
                    VolumeTDChartVM.DSValueDist.TSControl.TimeInterval)
                {
                    VolumeTDChartVM.ChangeDataSource(DBuilder.TFAnalytics.VolumeTotalDist[dsidx]);
                }
                break;

            case "SimControl":
                if (dsidx == 0)
                {
                    // pause / continue
                    if (BtnsSimControlVisibility != System.Windows.Visibility.Visible)
                    {
                        BtnsSimControlVisibility = System.Windows.Visibility.Visible;
                        SimControlEvent?.Invoke(0, 0);
                    }
                    else
                    {
                        BtnsSimControlVisibility = System.Windows.Visibility.Hidden;
                        SimControlEvent?.Invoke(1, 0);
                    }
                    NotifyPropertyChanged("BtnsSimControlVisibility");
                }
                else
                {
                    // forward
                    int nprints;
                    if (int.TryParse(TBoxSimControlForward, out nprints))
                    {
                        SimControlEvent?.Invoke(2, nprints);
                    }
                }
                break;
            }
        }