You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过后台代码正确重置ToggleButton的Interaction.Triggers?

问题:自动停止测量后ToggleButton需两次点击才能重新启动

我在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事件启动测量。

解决方案

方法一:确保属性通知与线程同步(推荐)

  1. 确认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));
}
  1. 由于定时器Tick事件可能在非UI线程执行,需切换到UI线程更新属性,修改OnStopMeasurementExecute中设置IsDataAcquisitionActivated的代码:
Application.Current.Dispatcher.Invoke(() =>
{
    IsDataAcquisitionActivated = false;
});

方法二:直接同步控件状态(不推荐,违反MVVM)

若不想修改ViewModel线程逻辑,可在停止操作后直接操作ToggleButton控件,确保状态同步:

Application.Current.Dispatcher.Invoke(() =>
{
    ButtonMeasurementConnect.IsChecked = false;
});

内容的提问来源于stack exchange,提问作者Dennis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:36:43