Coder323
Coder323

Reputation: 580

DispatcherTimer becomes slow for every minute in updating UI

I have implemented a DispatcherTimer with databinding which would act like a stopwatch or counting timer to display the time elapsed during an audio call. (as you can see in your mobile phones)

The following code is becoming slow for every minute by "1 second" which is not good in calculating the bill. Can you please tell me where I am wrong ?

System.Windows.Threading.DispatcherTimer dispatcherTimer; 
int seconds = 0;
public string Counter { get; set; }
public Timer()
    {
        InitializeComponent();
        this.DataContext = this;
        dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
        dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
        dispatcherTimer.Interval = new TimeSpan(0, 0, 1);         
    }
  private void dispatcherTimer_Tick(object sender, EventArgs e)
    {

       Counter = (seconds / 3600).ToString() + ":" + (seconds / 60).ToString("00") + ":" + (seconds % 60).ToString("00");
       NotifyPropertyChanged("Counter");
       seconds++;
    }

I compared this timer with other stop watches both in Internet and also in mobile, this timer is getting delayed by a second for each minute.

Upvotes: 1

Views: 2178

Answers (2)

peter
peter

Reputation: 13501

You are relying on the timer, and it seems to be consistently inaccurate by the same amount.

Why don't you take a point in time and store that,

private DateTime startTime;

public Timer()
{
    InitializeComponent();
    startTime = DateTime.Now;
}

private void dispatcherTimer_Tick(object sender, EventArgs e)
{
    Counter = (DateTime.Now - startTime).ToString();
    ...
}

Actually taking the code like this shows why you are having a problem. The ToString method there shows the counter more accurately including milliseconds, and it turns out the timer is not firing every 1 second, but more like every 1.01 seconds.

I am getting values like this,

1.008
1.02
1.031
1.03901

etc.

You can then replace the above with this,

private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        TimeSpan elapsedTime = (DateTime.Now - startTime);
        Counter = string.Format("{0:hh\\:mm\\:ss}", elapsedTime);

And it will be formatted like you had it before with no milliseconds.

Upvotes: 4

Darren Kopp
Darren Kopp

Reputation: 77687

You aren't guaranteed to have the event fire at exactly 1000ms interval. You should calculate the seconds in the event rather than incrementing your own field that holds seconds

Upvotes: 1

Related Questions