Search code examples
c#wpfdispatchertimer

Unable to correctly restart my DispatcherTimer


I am trying to implement a timer in my application with three buttons - Start, Stop and Restart.

The timer starts and stops fine. However, when I click on the restart button it starts from the previous value of seconds and minutes instead of starting at 0 and 0. I can't see what I'm doing wrong as I set seconds and minutes to 0 right in the start of the restart method itself.

eg: First time starts at 0 and goes on to 1, 2, 3. Stops at 3. When I restart, it starts from 2 and goes on to 4, 6... If I restart again it starts at 3 and goes on to 6, 9, 12...

Below is my code:

    public int seconds;
    public int minutes;
    public int hours;

    System.Windows.Threading.DispatcherTimer myTimer = new System.Windows.Threading.DispatcherTimer();

    private void Tick_Timer_Start(object sender, RoutedEventArgs e)
    {
        myTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
        myTimer.Tick += new EventHandler(Each_Tick);
        myTimer.Start();
    }

    private void Tick_Timer_Stop(object sender, RoutedEventArgs e)
    {
        myTimer.Stop();
    }

    private void Tick_Timer_Restart(object sender, RoutedEventArgs e)
    {
        seconds = 0;
        minutes = 0;
        Timertext.Text = "0 minutes : 0 seconds";
        myTimer.Interval = new TimeSpan(0, 0, 0, 0, 1000);
        myTimer.Tick += new EventHandler(Each_Tick);
        myTimer.Start();

    }

    private void Each_Tick(object o, EventArgs sender)
    {
        seconds = seconds + 1;

        if (seconds < 10 && minutes < 10)
        {
            Timertext.Text =  minutes.ToString() + " minutes : " + seconds.ToString() + " seconds";
        }
        else if (seconds > 59)
        {
            minutes = minutes + 1;
            seconds = 0;
            seconds = seconds + 1;
            Timertext.Text =  minutes.ToString() + " minutes : " + seconds.ToString() + " seconds";
        }
        else
        {
            Timertext.Text =  minutes.ToString() + " minutes : " + seconds.ToString() + " seconds";
        }
    }

Any help will be much appreciated.


Solution

  • All you need to do is to attach the Tick handler only once:

    private int seconds;
    private int minutes;
    private int hours;
    private DispatcherTimer myTimer = new DispatcherTimer();
    
    private void Initialize()
    {
        myTimer.Interval = TimeSpan.FromMilliseconds(1000);
        myTimer.Tick += Each_Tick;
    }
    
    private void Tick_Timer_Start(object sender, RoutedEventArgs e)
    {
        myTimer.Start();
    }
    
    private void Tick_Timer_Stop(object sender, RoutedEventArgs e)
    {
        myTimer.Stop();
    }
    
    private void Tick_Timer_Restart(object sender, RoutedEventArgs e)
    {
        myTimer.Stop();
        seconds = 0;
        minutes = 0;
        Timertext.Text = "0 minutes : 0 seconds";
        myTimer.Start();
    }
    
    private void Each_Tick(object o, EventArgs sender)
    {
        ...
    }
    

    Even simpler would be a solution where you would only have Start and Stop, without any need for a Restart:

    private int seconds;
    private int minutes;
    private int hours;
    private DispatcherTimer myTimer = new DispatcherTimer();
    
    private void Initialize()
    {
        myTimer.Interval = TimeSpan.FromMilliseconds(1000);
        myTimer.Tick += Each_Tick;
    }
    
    private void Tick_Timer_Start(object sender, RoutedEventArgs e)
    {
        myTimer.Stop();
        seconds = 0;
        minutes = 0;
        Timertext.Text = "0 minutes : 0 seconds";
        myTimer.Start();
    }
    
    private void Tick_Timer_Stop(object sender, RoutedEventArgs e)
    {
        myTimer.Stop();
    }
    
    private void Each_Tick(object o, EventArgs sender)
    {
        ...
    }