如何通过后台代码正确重置ToggleButton的Interaction.Triggers?
我在C#/WPF项目中使用带有Interaction.Triggers的ToggleButton控制测量启停,正常流程下按下按钮启动测量,再次按下停止并重置属性。但添加定时器自动停止功能后,定时器触发停止操作后,再次启动必须点击两次按钮——第一次点击只会触发StopMeasurementCommand,无法启动测量。
相关代码
XAML代码
<ToggleButton x:Name="ButtonMeasurementConnect" Grid.Row="5" Grid.Column="3" VerticalAlignment="Center" Content="{Binding ButtonDataAcquisitionName}" IsChecked="{Binding IsDataAcquisitionActivated, Mode=TwoWay}"> <i:Interaction.Triggers> <i:EventTrigger EventName="Checked"> <i:InvokeCommandAction Command="{Binding StartMeasurementCommand}"/> </i:EventTrigger> <i:EventTrigger EventName="Unchecked"> <i:InvokeCommandAction Command="{Binding StopMeasurementCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </ToggleButton>
ViewModel命令初始化
StartMeasurementCommand = new DelegateCommand(OnStartMeasurementExecute); StopMeasurementCommand = new DelegateCommand(OnStopMeasurementExecute);
OnStopMeasurementExecute方法
try { if (stopWatch.IsRunning) { stopWatch.Stop(); } _receivingDataLock = true; // 停止数据写入/消费与显示 _sourceDisplay.Cancel(); if (IsRecordingRequested) { _sourceWriter.Cancel(); } else { _sourceConsumer.Cancel(); } // 发送停止命令到设备 _dataAcquisition.StopDataAcquisition(); // 更新状态标记与UI文本 ButtonRecordingVisibility = Visibility.Hidden; IsDataAcquisitionActivated = false; IsDataAcquisitionDeactivated = true; ButtonDataAcquisitionName = "Start"; StatusMessage = IsRecordingRequested ? $"Recording stopped after {CurrentTime}" : $"Live data stopped after {CurrentTime}"; if (IsRecordingRequested) _recordedDataFile.Close(); } catch (Exception e) { Console.WriteLine("Exception in OnStopMeasurementExecute: " + e.Message); }
定时器Tick事件
void Stopwatch_Tick(object sender, EventArgs e) { if (stopWatch.IsRunning) { TimeSpan ts = stopWatch.Elapsed; CurrentTime = String.Format("{0:00}:{1:00}:{2:00}", ts.Minutes, ts.Seconds, ts.Milliseconds / 10); if ((IsTimerActivated) && (MeasureTime>0)) { if (ts.Seconds >= MeasureTime) OnStopMeasurementExecute(); } } }
问题原因
定时器触发OnStopMeasurementExecute时,虽然ViewModel中将IsDataAcquisitionActivated设为false,但ToggleButton的IsChecked状态未同步更新——界面上按钮文本显示为"Start",但控件实际的IsChecked仍为true。此时第一次点击按钮是将IsChecked从true改为false,触发Unchecked事件(即StopMeasurementCommand),第二次点击才会将IsChecked设为true,触发Checked事件启动测量。
解决方案
方法一:确保属性通知与线程同步(推荐)
- 确认
IsDataAcquisitionActivated属性正确实现INotifyPropertyChanged,变更时触发事件:
private bool _isDataAcquisitionActivated; public bool IsDataAcquisitionActivated { get => _isDataAcquisitionActivated; set { if (_isDataAcquisitionActivated != value) { _isDataAcquisitionActivated = value; OnPropertyChanged(nameof(IsDataAcquisitionActivated)); } } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
- 由于定时器Tick事件可能在非UI线程执行,需切换到UI线程更新属性,修改
OnStopMeasurementExecute中设置IsDataAcquisitionActivated的代码:
Application.Current.Dispatcher.Invoke(() => { IsDataAcquisitionActivated = false; });
方法二:直接同步控件状态(不推荐,违反MVVM)
若不想修改ViewModel线程逻辑,可在停止操作后直接操作ToggleButton控件,确保状态同步:
Application.Current.Dispatcher.Invoke(() => { ButtonMeasurementConnect.IsChecked = false; });
内容的提问来源于stack exchange,提问作者Dennis
相关产品推荐
相关产品推荐

