WPF DispatcherTimer пропускает интервалы при перезапуске

Я боролся с этим последние несколько дней и надеюсь, что вы все сможете мне помочь. Я создаю приложение таймера WPF и использую DispatcherTimer, чтобы отсчитывать время вверх в минутах. Когда я запускаю таймер изначально, он работает отлично. Однако, когда я останавливаю таймер, а затем снова включаю его, он начинает считать по 2. Если я сделаю это снова, он будет считаться по 3 и так далее. Я не совсем уверен в том, что все можно сделать с помощью DispatcherTimer, так что здесь мне действительно нужна помощь.

Это начальная функция, которая вызывается при нажатии кнопки «Пуск».

private void TimerStart(object sender, RoutedEventArgs e)
{
    if ((string) TimerBlock.Content == "--:--")
    {
        TimerBlock.Content = "00:00";
        TimerTray.Content = "00:00";
    }
    else
    {
        var timerString = TimerBlock.Content.ToString();
        _minute = Convert.ToInt32(timerString.Substring(0, 2));
        _hour = Convert.ToInt32(timerString.Substring(3, 2));
    }
    _timer.Interval = TimerBlock.Content.ToString();
    _timer.Tick += dispatcherTimer_tick;
    _timer.Start();
    TaskBarStop.IsChecked = false;
    TimerStatus.Content = "The Timer Has Started";
    TimerStatus.Foreground = System.Windows.Media.Brushes.DarkGreen;
    TimerTrayStatus.Content = "STARTED";
    TimerTrayStatus.Foreground = System.Windows.Media.Brushes.DarkGreen;
    StartButton.IsEnabled = false;
    StopButton.IsEnabled = true;
}

Вот галочка.

private void dispatcherTimer_tick(object sender, EventArgs e)
{
    if (_minute++ == 60)
    {
        _minute = 0;
        _hour++;
    }

    if (_hour < 10 && _minute < 10)
        TimerBlock.Content = "0" + _hour + ":0" + _minute;
    else if (_hour < 10 && _minute >= 10)
        TimerBlock.Content = "0" + _hour + ":" + _minute;
    else if (_hour >= 10 && _minute < 10)
        TimerBlock.Content = _hour + ":0" + _minute;
    else
        TimerBlock.Content = _hour + ":" + _minute;

    TimerTray.Content = TimerBlock.Content;
    CommandManagaer.InvalidateRequerySuggested();
}

А вот метод, вызываемый при нажатии кнопки остановки.

private void TimerStop(object sender, RoutedEventArgs e)
{
    _timer.Stop();
    TaskBarStart.IsChecked = false;
    TimerStatus.Content = "The Timer Has Stopped";
    TimerStatus.Foreground = System.Windows.Media.Brushes.DarkRed;
    TimerTrayStatus.Content = "STOPPED";
    TimerTrayStatus.Foreground = System.Windows.Media.Brushes.DarkRed;
    StartButton.IsEnabled = true;
    StopButton.IsEnabled = false;

    using (var db = new TimerDb())
    {            
        var timer = TimerBlock.Content.ToString();
        var session = new TimerSession();

        if (db.TemporaryTimeActivities.Any())
            session.SetTimeActivity(timer);            
        else
            session.UpdateTime(timer);
    }
}

По сути, я не могу понять, это просто что-то маленькое, на что я не обращаю внимания, или я испортил что-то очень плохое в другом месте. Любая помощь будет принята с благодарностью. Есть ли что-то, что я вставил в код, что заставляет его увеличивать интервал на 1 при каждом перезапуске?


person Atarinerd80    schedule 08.12.2014    source источник


Ответы (1)


Вы должны присоединять обработчик Tick только один раз, а не каждый раз при запуске таймера.

Так что переместите линию

_timer.Tick += dispatcherTimer_tick;

из метода TimerStart и поместите его, например, в конструкторе Window или UserControl.

Также вы должны убедиться, что таймер Interval установлен правильно. Похоже, вы хотите, чтобы обработчик Tick вызывался раз в минуту, поэтому вам следует установить его соответствующим образом:

_timer.Interval = TimeSpan.FromMinutes(1.0);

Также было бы проще (и точнее) не считать минуты самостоятельно, а вместо этого использовать структуры DateTime и TimeSpan. Используйте свойство DateTime.Now, чтобы сохранить время начала в поле типа DateTime в методе TimerStart.

private DateTime started;

private void TimerStart(object sender, RoutedEventArgs e)
{
    ...
    started = DateTime.Now;
}

и воспользуйтесь функциями форматирования строк класса TimeSpan:

private void dispatcherTimer_tick(object sender, EventArgs e)
{
    var elapsedTime = DateTime.Now - started;
    TimerBlock.Content = elapsedTime.ToString(@"hh\:mm");
    ...
}
person Clemens    schedule 08.12.2014
comment
Большое спасибо за Вашу помощь! Я не знал, что вы вызываете обработчик Tick только один раз. А структуры DateTime и TimeSpan делают этот вид намного чище. Спасибо! - person Atarinerd80; 09.12.2014