async Task filterStart(string csvFilterString)
        {
            if (!_loaded)
            {
                return;
            }

            Debug.WriteLine($"■■■ filterStart()");

            App.Synth.SpeakAsyncCancelAll();
            Bpr.BeepFD(12000, 33); // wake monitor speakers

            await reLoadTxCore();

            if (string.IsNullOrEmpty(csvFilterString))
            {
                App.Synth.SpeakAsync("Clear!");
                filterTxns(csvFilterString, _txCatgry);
            }
            else
            {
                var ta = csvFilterString.Split(new[] { '`', '>', '\\', '/' });
                if (ta.Length > 1)
                {
                    App.Synth.SpeakAsync($"{ta.Length}-part filter");

                    if (string.IsNullOrEmpty(ta[0]) && string.IsNullOrEmpty(ta[1]))
                    {
                        App.Synth.SpeakAsync("Still Empty."); return;
                    }
                    if (!string.IsNullOrEmpty(ta[0]))
                    {
                        if (!decimal.TryParse(ta[0], out var amt))
                        {
                            App.Synth.SpeakAsync("1st must be number."); return;
                        }

                        if (!decimal.TryParse(tRng.Text, out var rng))
                        {
                            tRng.Text = (rng = 0m).ToString();
                        }
                        //App.Synth.SpeakAsync("Multi.");
                        filterTxns(csvFilterString.Substring(ta[0].Length + 1), _txCatgry, amt, rng);
                    }
                    else if (!string.IsNullOrEmpty(ta[1])) // explicit by string
                    {
                        //App.Synth.SpeakAsync("Filter by text.");
                        filterTxns(ta[1], _txCatgry);
                    }
                }
                else // == 1
                {
                    if (decimal.TryParse(csvFilterString, out var amt))
                    {
                        if (!decimal.TryParse(tRng.Text, out var rng))
                        {
                            tRng.Text = (rng = 0m).ToString();
                        }
                        //App.Synth.SpeakAsync("Filter by money.");
                        filterTxns("", _txCatgry, amt, rng);
                    }
                    else
                    {
                        //App.Synth.SpeakAsync("Filter by text.");
                        filterTxns(csvFilterString, _txCatgry);
                    }
                }
            }

            _txCoreV2_Root_VwSrc.Source = _core;

            if (chkInfer.IsChecked == true)
            {
                var catIds = _core.Select(r => r.TxCategory.Id).Distinct().Where(r => r != 3); // Debug.WriteLine($"catIds.Count() = {catIds.Count()}");
                filterCategoryByIdList(catIds);
            }

            updateTitle();
            Bpr.OkFaF();
        }