WPF DispatcherTimer 在恢复时不保持时间

WPF DispatcherTimer doesn't keep time when resumed

当您在 DispatcherTimer 中将 属性 IsEnabled 设置为 false 时,假设计时器会在后台保持其状态,或者它会停止并重置?在下面的示例中,定时器间隔为 5 秒,如果您 运行 应用程序,如果您单击按钮以在 4 秒时禁用定时器,如果您再次单击该按钮以在 7 秒时启用它(例如) , 计时器事件不会在一秒后的 8s 时触发,而是在 12s = 7s + 5s 时触发。 timer.IsEnabled=false 似乎重置了计时器间隔。有没有其他方法在禁用时保持定时器状态?

该应用程序有两个标签 timerLabel 和 statusLabel 以及按钮。我这里没有足够的声誉点数来 post 图片。

namespace WpfApplication1 {

public partial class MainWindow : Window {

    public MainWindow() {
        InitializeComponent();
    }

    int ticksCounter = 0;  

    System.Windows.Threading.DispatcherTimer timer;

    private void Window_Loaded(object sender, RoutedEventArgs e) {
        timer = new System.Windows.Threading.DispatcherTimer();
        timer.Tick += new EventHandler(timer_Tick);
        timer.Interval = new TimeSpan(0, 0, 0, 5, 0);  // Sets 5 s. interval
        timer.Start();
    }

    private void timer_Tick(object sender, EventArgs e) {
        ticksCounter ++;
        timeLabel.Content = "Ticks = " + ticksCounter.ToString();
    }

    private void button_Click(object sender, RoutedEventArgs e) {
        if (timer.IsEnabled) {
            timer.IsEnabled = false;
            statusLabel.Content = "OFF";
            boton.Content = "Enable";
        }
        else {
            timer.IsEnabled = true;
            statusLabel.Content = "ON";
            boton.Content = "Disable";
        }
    }

}
}

DispatcherTimer 总是在重新启动时重新开始计时,无论是通过调用 Start() 还是将 IsEnabled 设置为 true。如果您希望计时器从间隔的中间恢复,您需要自己实现。例如,通过维护一个 Stopwatch 来测量自最近一次滴答以来经过的时间,并在您重新启动它时减去第一个间隔,将间隔恢复为 Tick 事件处理程序中所需的常规间隔.

这是一个说明基本思想的代码示例:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        _timer = new DispatcherTimer();
        _timer.Tick += _timer_Tick;
    }

    void _timer_Tick(object sender, EventArgs e)
    {
        _timer.Interval = _baseInterval;
        _stopWatch.Restart();
    }

    private TimeSpan _baseInterval = TimeSpan.FromSeconds(5);
    private DispatcherTimer _timer;
    private Stopwatch _stopWatch = new Stopwatch();

    // Call from appropriate location to toggle timer, e.g. in a button's
    // Click event handler.
    private void ToggleTimer()
    {
        if (_timer.IsEnabled)
        {
            _timer.IsEnabled = false;
            _stopWatch.Stop();
            button1.Content = "Start";
        }
        else
        {
            _timer.Interval = _baseInterval - _stopWatch.Elapsed;
            _stopWatch.Restart();
            _timer.IsEnabled = true;
        }
    }
}

我知道它已经过去很长时间了,但我在使用这个示例时注意到要使其正确,您需要进行 1 处小改动。

ToogleTimer() 函数中而不是调用 _stopWatch.Restart() 调用 _stopWatch.Start()

不同之处在于,在上面的代码中,如果您在 1 个间隔内暂停更多次,将会产生副作用,因为每次您恢复秒表都会重置(它应该只在 dispathcer 的 Tick 事件中重置)。