Question

I have an application that requires multiple countdown timers to run (some simultaneously). They also update UI elements with the time remaining on the countdown. I have tried using DispatcherTimer for it's easy way to interact with UI elements. However, over a 300 second countdown, it becomes out of sync with real time (because of the heavy UI updating) to the point that I get 30 seconds left on the timer when it should be 0.

I then tried switching to a System.Threading.Timer (code below). Now, the timer is spot-on and in sync with real life time. However, the Timer stops ticking after a random number of ticks (between 3 seconds and 60 seconds). I suspect it's either the garbage collector kicking in, or the Invoke (used for updating the UI) but don't really have the knowledge to continue down this path. Can anybody give me any insight as to why the timer randomly stops ?

private int counter = 500;    
private void btnTopBlue_Click(object sender, RoutedEventArgs e)
{
    btnTopBlue.Content = counter.ToString();
    Timer dt = new Timer(topBlue_Tick, null, 1000, 1000);
}
private void topBlue_Tick(object sender)
{
     if (counter > 0)
     {
         counter--;
         Dispatcher.BeginInvoke(() => btnTopBlue.Content = counter.ToString());    
     }
     else
         ((Timer)sender).Dispose();
 }
Was it helpful?

Solution

Don't count. Compare current time to the start time of the timer, and do the math. That way, even if you miss a half second here and a half second there, you'll still be spot on time.

Consider this code:

    private static DateTime EndTime { get; set; }

    private void Button_Click(object sender, RoutedEventArgs e)
    {

        DispatcherTimer dt = new DispatcherTimer();
        dt.Interval = TimeSpan.FromSeconds(.1);


        dt.Tick += (s, evt) =>
                       {
                           var remaining = EndTime - DateTime.Now;

                           timeRemaining.Text = string.Format("{0:0.0}", remaining.TotalSeconds);

                           if(remaining.TotalSeconds <= 0)
                           {
                               dt.Stop();
                           }
                       };

        EndTime = DateTime.Now + TimeSpan.FromSeconds(30);
        dt.Start();

    }

OTHER TIPS

This happened to me for a service I was writing. The timer would eventually stop, and debugging the process found that the threads had been garbage collected. It was suggested to me that setting the .IsBackground = true property would fix this. I ended up doing something different, so I didn't get a chance to try this. It may help you though.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top