using DeviceCommand.Devices; using OxyPlot; using OxyPlot.Axes; using OxyPlot.Legends; using OxyPlot.Series; using Prism.Commands; using Prism.Ioc; using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; using UIShare.GlobalVariable; using UIShare.ViewModelBase; namespace PowerAdaptabilityModule.ViewModels { /// /// 电源适应性测试 ViewModel(Chroma61800 交流源一拖三): /// 左侧为设备命令面板(三相输出设置 + LIST 模式),右侧为 A/B/C 三相实时波形图表。 /// public class PowerAdaptabilityViewModel : NavigateViewModelBase, IDisposable { #region 常量 /// 采样周期(毫秒) private const int SampleIntervalMs = 1000; /// 合成正弦波的分段数(0~360°,每 2° 一个点,共 181 点) private const int SinePoints = 180; /// 三相相位偏移(°):A=0,B=-120,C=+120 private static readonly double[] PhaseOffsetDeg = { 0, -120, 120 }; /// 三相曲线配色:A 红、B 绿、C 蓝(三张图统一,便于对照) private static readonly OxyColor[] PhaseColors = { OxyColor.FromRgb(0xE5, 0x39, 0x35), OxyColor.FromRgb(0x43, 0xA0, 0x47), OxyColor.FromRgb(0x1E, 0x88, 0xE5) }; #endregion #region 私有字段 private readonly DeviceManager _dm; private readonly GlobalInfo _globalInfo; private Chroma61800? _dev; private CancellationTokenSource? _cmdCts; private CancellationTokenSource? _sampleCts; // 三相正弦曲线:按物理量分组(电压 / 电流 / 功率),每组含 A/B/C 三相 private readonly LineSeries _voltA, _voltB, _voltC; private readonly LineSeries _currA, _currB, _currC; private readonly LineSeries _powA, _powB, _powC; #endregion #region 设备状态属性 private string _deviceName = "Chroma61800"; public string DeviceName { get => _deviceName; set => SetProperty(ref _deviceName, value); } private bool _isConnected; public bool IsConnected { get => _isConnected; set => SetProperty(ref _isConnected, value); } private bool _isBusy; public bool IsBusy { get => _isBusy; set => SetProperty(ref _isBusy, value); } private bool _isSampling; /// 是否正在采集波形数据 public bool IsSampling { get => _isSampling; set => SetProperty(ref _isSampling, value); } #endregion #region 三相图表(按物理量分图:电压 / 电流 / 功率,每图叠加 A/B/C 三相正弦) /// 三相电压波形图表 public PlotModel VoltagePlot { get; } /// 三相电流波形图表 public PlotModel CurrentPlot { get; } /// 三相功率波形图表 public PlotModel PowerPlot { get; } #endregion #region 实时测量值 private double _voltageA; public double VoltageA { get => _voltageA; set => SetProperty(ref _voltageA, value); } private double _currentA; public double CurrentA { get => _currentA; set => SetProperty(ref _currentA, value); } private double _voltageB; public double VoltageB { get => _voltageB; set => SetProperty(ref _voltageB, value); } private double _currentB; public double CurrentB { get => _currentB; set => SetProperty(ref _currentB, value); } private double _voltageC; public double VoltageC { get => _voltageC; set => SetProperty(ref _voltageC, value); } private double _currentC; public double CurrentC { get => _currentC; set => SetProperty(ref _currentC, value); } private double _frequencyNow; /// 当前输出频率 (Hz) public double FrequencyNow { get => _frequencyNow; set => SetProperty(ref _frequencyNow, value); } private double _powerNow; /// 当前真实输出功率 (W) public double PowerNow { get => _powerNow; set => SetProperty(ref _powerNow, value); } #endregion #region 输入参数(三相输出设置) private double _voltage = 220; /// 待设置的交流电压 (V) public double Voltage { get => _voltage; set => SetProperty(ref _voltage, value); } private double _frequency = 50; /// 待设置的输出频率 (Hz) public double Frequency { get => _frequency; set => SetProperty(ref _frequency, value); } private string _waveform = "SINE"; /// 波形选择 public string Waveform { get => _waveform; set => SetProperty(ref _waveform, value); } private string _couplingMode = "AC"; /// 输出耦合模式 (AC / DC / ACDC) public string CouplingMode { get => _couplingMode; set => SetProperty(ref _couplingMode, value); } private string _threePhaseRelation = "BALANCE"; /// 三相关系 (INDEPEND / SAMEFREQ / BALANCE) public string ThreePhaseRelation { get => _threePhaseRelation; set => SetProperty(ref _threePhaseRelation, value); } #endregion #region 输入参数(LIST 模式) private string _listCoupling = "NONE"; /// 列表耦合模态 (ALL / NONE) public string ListCoupling { get => _listCoupling; set => SetProperty(ref _listCoupling, value); } private string _listTrigger = "AUTO"; /// 列表触发形态 (AUTO / MANUAL / EXCITE) public string ListTrigger { get => _listTrigger; set => SetProperty(ref _listTrigger, value); } private int _listCount = 1; /// 列表执行次数 (0 ~ 65535) public int ListCount { get => _listCount; set => SetProperty(ref _listCount, value); } private string _listTimeBase = "TIME"; /// 列表时间基础 (TIME / CYCLE) public string ListTimeBase { get => _listTimeBase; set => SetProperty(ref _listTimeBase, value); } private string _listVoltAcStartText = ""; /// AC 起始电压序列(逗号分隔,如 0,50,100,150) public string ListVoltAcStartText { get => _listVoltAcStartText; set => SetProperty(ref _listVoltAcStartText, value); } private string _listVoltAcEndText = ""; /// AC 结束电压序列(逗号分隔) public string ListVoltAcEndText { get => _listVoltAcEndText; set => SetProperty(ref _listVoltAcEndText, value); } private string _listFreqStartText = ""; /// 起始频率序列(逗号分隔,如 50,60,50) public string ListFreqStartText { get => _listFreqStartText; set => SetProperty(ref _listFreqStartText, value); } private string _listFreqEndText = ""; /// 结束频率序列(逗号分隔) public string ListFreqEndText { get => _listFreqEndText; set => SetProperty(ref _listFreqEndText, value); } private string _listDwellText = ""; /// 静止时间序列(ms,逗号分隔,如 500,500,500) public string ListDwellText { get => _listDwellText; set => SetProperty(ref _listDwellText, value); } private string _listDegrText = ""; /// 相位角度序列(°,逗号分隔) public string ListDegrText { get => _listDegrText; set => SetProperty(ref _listDegrText, value); } private string _listShapeText = ""; /// 波形缓冲顺序(A/B,逗号分隔,如 A,B,A) public string ListShapeText { get => _listShapeText; set => SetProperty(ref _listShapeText, value); } #endregion #region 下拉选项 public IReadOnlyList WaveformOptions { get; } = new[] { "SINE", "SQUA", "CSIN" }; public IReadOnlyList CouplingOptions { get; } = new[] { "AC", "DC", "ACDC" }; public IReadOnlyList RelationOptions { get; } = new[] { "INDEPEND", "SAMEFREQ", "BALANCE" }; public IReadOnlyList ListCouplingOptions { get; } = new[] { "ALL", "NONE" }; public IReadOnlyList ListTriggerOptions { get; } = new[] { "AUTO", "MANUAL", "EXCITE" }; public IReadOnlyList ListTimeBaseOptions { get; } = new[] { "TIME", "CYCLE" }; #endregion #region 日志 private string _responseLog = ""; /// 操作与采样日志 public string ResponseLog { get => _responseLog; set => SetProperty(ref _responseLog, value); } #endregion #region 命令 public ICommand QueryIdnCommand { get; } public ICommand ResetCommand { get; } public ICommand OutputOnCommand { get; } public ICommand OutputOffCommand { get; } public ICommand RelayOnCommand { get; } public ICommand RelayOffCommand { get; } public ICommand ApplyCouplingCommand { get; } public ICommand SetThreePhaseModeCommand { get; } public ICommand SetSinglePhaseModeCommand { get; } public ICommand ApplyRelationCommand { get; } public ICommand SetVoltageCommand { get; } public ICommand SetFrequencyCommand { get; } public ICommand SetWaveformCommand { get; } public ICommand SetFixedModeCommand { get; } public ICommand EnterListModeCommand { get; } public ICommand ApplyListBasicCommand { get; } public ICommand ApplyListSequencesCommand { get; } public ICommand ListStartCommand { get; } public ICommand ListStopCommand { get; } public ICommand StartSamplingCommand { get; } public ICommand StopSamplingCommand { get; } public ICommand ClearChartsCommand { get; } #endregion public PowerAdaptabilityViewModel(IContainerProvider containerProvider) : base(containerProvider) { _dm = containerProvider.Resolve(); _globalInfo = containerProvider.Resolve(); // 初始化三相图表(按物理量分图,每图叠加 A/B/C 三相正弦) VoltagePlot = BuildSinePlot("三相电压", "V"); CurrentPlot = BuildSinePlot("三相电流", "A"); PowerPlot = BuildSinePlot("三相功率", "W"); (_voltA, _voltB, _voltC) = AddThreePhaseSeries(VoltagePlot); (_currA, _currB, _currC) = AddThreePhaseSeries(CurrentPlot); (_powA, _powB, _powC) = AddThreePhaseSeries(PowerPlot); #region 命令初始化 QueryIdnCommand = new DelegateCommand(async () => await Exec(async () => Log("IDN: " + await _dev!.查询设备信息Async(Ct())))); ResetCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.复位Async(Ct()); Log("设备已复位"); })); OutputOnCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置输出开关Async(true, Ct()); Log("输出已开启"); })); OutputOffCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置输出开关Async(false, Ct()); Log("输出已关闭"); })); RelayOnCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置输出继电器Async(true, Ct()); Log("输出继电器已开启"); })); RelayOffCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置输出继电器Async(false, Ct()); Log("输出继电器已关闭"); })); ApplyCouplingCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置耦合模式Async(CouplingMode, Ct()); Log($"耦合模式={CouplingMode}"); })); SetThreePhaseModeCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置单三相模式Async(true, Ct()); Log("已切换为三相模式"); })); SetSinglePhaseModeCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置单三相模式Async(false, Ct()); Log("已切换为单相模式"); })); ApplyRelationCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置三相关系Async(ThreePhaseRelation, Ct()); Log($"三相关系={ThreePhaseRelation}"); })); SetVoltageCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置交流电压Async(Voltage, Ct()); Log($"交流电压={Voltage} V"); })); SetFrequencyCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置频率Async(Frequency, Ct()); Log($"输出频率={Frequency} Hz"); })); SetWaveformCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置波形Async(Waveform, Ct()); Log($"波形={Waveform}"); })); SetFixedModeCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置操作模态Async("FIXED", Ct()); Log("已切换为 FIXED 固定模式"); })); EnterListModeCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置操作模态Async("LIST", Ct()); Log("已切换为 LIST 模式"); })); ApplyListBasicCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置列表耦合模态Async(ListCoupling, Ct()); await _dev!.设置列表触发形态Async(ListTrigger, Ct()); await _dev!.设置列表执行次数Async(ListCount, Ct()); await _dev!.设置列表时间基础Async(ListTimeBase, Ct()); Log($"LIST 基础配置:耦合={ListCoupling} 触发={ListTrigger} 次数={ListCount} 时基={ListTimeBase}"); })); ApplyListSequencesCommand = new DelegateCommand(async () => await Exec(async () => { int applied = 0; var vAcStart = ParseDoubles(ListVoltAcStartText); if (vAcStart.Length > 0) { await _dev!.设置列表AC起始电压顺序Async(vAcStart, Ct()); applied++; } var vAcEnd = ParseDoubles(ListVoltAcEndText); if (vAcEnd.Length > 0) { await _dev!.设置列表AC结束电压顺序Async(vAcEnd, Ct()); applied++; } var fStart = ParseDoubles(ListFreqStartText); if (fStart.Length > 0) { await _dev!.设置列表起始频率顺序Async(fStart, Ct()); applied++; } var fEnd = ParseDoubles(ListFreqEndText); if (fEnd.Length > 0) { await _dev!.设置列表结束频率顺序Async(fEnd, Ct()); applied++; } var dwell = ParseDoubles(ListDwellText); if (dwell.Length > 0) { await _dev!.设置列表静止时间顺序Async(dwell, Ct()); applied++; } var degr = ParseDoubles(ListDegrText); if (degr.Length > 0) { await _dev!.设置列表相位角度顺序Async(degr, Ct()); applied++; } var shapes = ParseShapes(ListShapeText); if (shapes.Length > 0) { await _dev!.设置列表波形顺序Async(shapes, Ct()); applied++; } Log(applied > 0 ? $"已下发 {applied} 组列表序列" : "没有可下发的列表序列(请先填写序列文本框)"); })); ListStartCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.设置操作模态Async("LIST", Ct()); await _dev!.触发列表执行Async(true, Ct()); Log("LIST 已开始执行"); })); ListStopCommand = new DelegateCommand(async () => await Exec(async () => { await _dev!.触发列表执行Async(false, Ct()); Log("LIST 已停止执行"); })); StartSamplingCommand = new DelegateCommand(StartSampling); StopSamplingCommand = new DelegateCommand(StopSampling); ClearChartsCommand = new DelegateCommand(ClearCharts); #endregion Initialize(); } #region 初始化 / 导航 /// /// 查找 Chroma61800 设备实例:优先当前作用域 DeviceManager,回退全局 HardwarePool(跨作用域共享实例)。 /// private void Initialize() { Chroma61800? found = null; string? fn = null; foreach (var kv in _dm.DeviceMap) { if (kv.Value is Chroma61800 it) { found = it; fn = kv.Key; break; } } if (found == null) { foreach (var kv in _globalInfo.HardwarePool) { if (kv.Value.IsValueCreated && kv.Value.Value is Chroma61800 c) { found = c; fn = kv.Key; break; } } } _dev = found; DeviceName = fn ?? "Chroma61800 (未找到)"; IsConnected = _dev?.IsConnected ?? false; Log(found != null ? $"已关联设备 [{DeviceName}],连接:{(IsConnected ? "已连接" : "未连接")}" : "未找到 Chroma61800 设备,请先在设置界面添加并启用该设备"); } public override void OnNavigatedTo(NavigationContext navigationContext) { Initialize(); } public override void OnNavigatedFrom(NavigationContext navigationContext) { // 离开页面时停止采样,避免后台持续占用设备通信 StopSampling(); } #endregion #region 数据采集 private void StartSampling() { if (_dev == null) { Log("未关联 Chroma61800 设备,无法采集"); return; } if (IsSampling) return; IsSampling = true; _sampleCts = new CancellationTokenSource(); var token = _sampleCts.Token; _ = Task.Run(() => SamplingLoopAsync(token), token); Log($"开始采集(周期 {SampleIntervalMs} ms)"); } private void StopSampling() { if (!IsSampling) return; IsSampling = false; try { _sampleCts?.Cancel(); } catch { } _sampleCts?.Dispose(); _sampleCts = null; Log("停止采集"); } /// /// 采样循环:逐相读取交流电压/电流,合成波形;并刷新频率与功率实时值。 /// 说明:Chroma61800 类现有测量方法面向"活动相位",三相逐一调用读取; /// 如设备需要按相切换后读取,可在每相读取前补充相位选择命令。 /// private async Task SamplingLoopAsync(CancellationToken token) { while (!token.IsCancellationRequested) { try { if (_dev != null && _dev.IsConnected) { // A 相 double vA = await _dev.读取交流电压Async(token); double iA = await _dev.读取交流电流Async(token); // B 相 double vB = await _dev.读取交流电压Async(token); double iB = await _dev.读取交流电流Async(token); // C 相 double vC = await _dev.读取交流电压Async(token); double iC = await _dev.读取交流电流Async(token); // 设备级:频率与功率 double freq = await _dev.读取频率Async(token); double power = await _dev.读取真实功率Async(token); var dispatcher = Application.Current?.Dispatcher; if (dispatcher != null) { _ = dispatcher.BeginInvoke(new Action(() => { RegenerateWaveforms(vA, iA, vB, iB, vC, iC, freq, power); IsConnected = _dev.IsConnected; })); } } } catch (OperationCanceledException) { break; } catch (Exception ex) { Log($"采样异常:{ex.Message}"); } try { await Task.Delay(SampleIntervalMs, token); } catch (OperationCanceledException) { break; } } } /// /// 根据实测 RMS 值合成三相正弦波并刷新三张图表(UI 线程调用)。 /// 横轴为相位角 0~360°,纵轴对称显示正负半周;电压/电流峰值 = √2 × RMS, /// 三相相位互差 120°(A=0,B=-120,C=+120)。设备仅提供 RMS 标量,故为示意波形。 /// private void RegenerateWaveforms(double vA, double iA, double vB, double iB, double vC, double iC, double freq, double power) { // 电压三相 RegenerateSine(_voltA, vA, PhaseOffsetDeg[0]); RegenerateSine(_voltB, vB, PhaseOffsetDeg[1]); RegenerateSine(_voltC, vC, PhaseOffsetDeg[2]); // 电流三相 RegenerateSine(_currA, iA, PhaseOffsetDeg[0]); RegenerateSine(_currB, iB, PhaseOffsetDeg[1]); RegenerateSine(_currC, iC, PhaseOffsetDeg[2]); // 功率三相(设备仅提供总有功,平衡三相每相 ≈ 总功率 / 3,按正弦示意呈现正负半周) double pPhase = power / 3.0; RegenerateSine(_powA, pPhase, PhaseOffsetDeg[0]); RegenerateSine(_powB, pPhase, PhaseOffsetDeg[1]); RegenerateSine(_powC, pPhase, PhaseOffsetDeg[2]); // 实时数值 VoltageA = vA; CurrentA = iA; VoltageB = vB; CurrentB = iB; VoltageC = vC; CurrentC = iC; FrequencyNow = freq; PowerNow = power; // 纵轴对称范围(取该图三相峰值最大值并留 15% 余量,确保正负半周完整可见) SetSymmetricAxis(VoltagePlot, vA, vB, vC); SetSymmetricAxis(CurrentPlot, iA, iB, iC); SetSymmetricAxis(PowerPlot, pPhase); VoltagePlot.InvalidatePlot(true); CurrentPlot.InvalidatePlot(true); PowerPlot.InvalidatePlot(true); } /// 按 RMS 幅值与相位偏移,生成 0~360° 一个完整周期的正弦曲线点(峰值 = √2 × RMS)。 private static void RegenerateSine(LineSeries series, double rms, double phaseDeg) { series.Points.Clear(); double peak = Math.Sqrt(2) * rms; double phaseRad = phaseDeg * Math.PI / 180.0; for (int i = 0; i <= SinePoints; i++) { double deg = 360.0 * i / SinePoints; double rad = deg * Math.PI / 180.0 + phaseRad; series.Points.Add(new DataPoint(deg, peak * Math.Sin(rad))); } } /// 设置纵轴对称范围(-peak ~ +peak);无输出时回退到 ±1 避免坐标轴退化。 private static void SetSymmetricAxis(PlotModel plot, params double[] rmsValues) { double maxRms = rmsValues.Max(); double peak = Math.Sqrt(2) * maxRms * 1.15; if (peak <= 0) peak = 1; if (plot.Axes.OfType().FirstOrDefault() is { } axis) { axis.Minimum = -peak; axis.Maximum = peak; } } private void ClearCharts() { foreach (var s in new[] { _voltA, _voltB, _voltC, _currA, _currB, _currC, _powA, _powB, _powC }) { s.Points.Clear(); } VoltagePlot.InvalidatePlot(true); CurrentPlot.InvalidatePlot(true); PowerPlot.InvalidatePlot(true); Log("已清空波形数据"); } #endregion #region 图表构建 /// /// 构建正弦波图表:横轴为相位角 0~360°,纵轴为对应物理量(对称显示正负半周),含图例。 /// /// 图表标题(如“三相电压”) /// 纵轴单位(V / A / W) private static PlotModel BuildSinePlot(string title, string unit) { var pm = new PlotModel { Title = $"{title} ({unit})", PlotAreaBorderColor = OxyColors.LightGray, Background = OxyColors.White }; pm.Axes.Add(new LinearAxis { Position = AxisPosition.Bottom, Title = "相位角 (°)", Minimum = 0, Maximum = 360, MajorStep = 45, MinorStep = 15, StringFormat = "0", MajorGridlineStyle = LineStyle.Dot, MinorGridlineStyle = LineStyle.None }); pm.Axes.Add(new LinearAxis { Position = AxisPosition.Left, Title = unit, Minimum = -1, Maximum = 1, MajorGridlineStyle = LineStyle.Dot, MinorGridlineStyle = LineStyle.None }); pm.Legends.Add(new Legend { LegendPosition = LegendPosition.RightTop, LegendBackground = OxyColor.FromAColor(200, OxyColors.White), LegendBorder = OxyColors.LightGray }); return pm; } /// 向图表添加 A/B/C 三相正弦曲线(红/绿/蓝,与三张图配色一致)。 private static (LineSeries A, LineSeries B, LineSeries C) AddThreePhaseSeries(PlotModel plot) { var a = NewPhaseSeries("A 相", PhaseColors[0]); var b = NewPhaseSeries("B 相", PhaseColors[1]); var c = NewPhaseSeries("C 相", PhaseColors[2]); plot.Series.Add(a); plot.Series.Add(b); plot.Series.Add(c); return (a, b, c); } /// 创建一条相曲线(无标记点、平滑线条)。 private static LineSeries NewPhaseSeries(string title, OxyColor color) => new LineSeries { Title = title, Color = color, StrokeThickness = 1.8, MarkerType = MarkerType.None }; #endregion #region 辅助 /// 创建 10 秒超时的取消令牌(命令用)。 private CancellationToken Ct() => (_cmdCts = new CancellationTokenSource(TimeSpan.FromSeconds(10))).Token; /// 统一的设备命令执行包装:防重入、异常捕获与日志。 private async Task Exec(Func action) { if (_dev == null) { Log("错误:未找到 Chroma61800 设备实例,请检查设备配置"); return; } if (IsBusy) return; IsBusy = true; try { await action(); IsConnected = _dev.IsConnected; } catch (OperationCanceledException) { Log("命令超时或已取消"); } catch (Exception ex) { Log($"错误:{ex.Message}"); } finally { IsBusy = false; } } /// 线程安全的日志输出(自动切回 UI 线程,保留最近内容)。 private void Log(string message) { var dispatcher = Application.Current?.Dispatcher; if (dispatcher != null && !dispatcher.CheckAccess()) { _ = dispatcher.BeginInvoke(new Action(() => Log(message))); return; } var line = $"[{DateTime.Now:HH:mm:ss}] {message}"; ResponseLog = ResponseLog.Length > 6000 ? line + "\n" + ResponseLog[..4000] : line + "\n" + ResponseLog; } /// 解析逗号/空格/分号分隔的数值序列。 private static double[] ParseDoubles(string text) { if (string.IsNullOrWhiteSpace(text)) return Array.Empty(); return text.Split(new[] { ',', ',', ' ', '\t', ';' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => double.TryParse(s.Trim(), out double v) ? (double?)v : null) .Where(v => v.HasValue) .Select(v => v!.Value) .ToArray(); } /// 解析波形缓冲顺序(A/B)序列。 private static string[] ParseShapes(string text) { if (string.IsNullOrWhiteSpace(text)) return Array.Empty(); return text.Split(new[] { ',', ',', ' ', '\t', ';' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim().ToUpperInvariant()) .ToArray(); } #endregion public void Dispose() { StopSampling(); try { _cmdCts?.Cancel(); } catch { } _cmdCts?.Dispose(); } } }