0

I'm programming in c#(WPF). I'm trying to call a function repetitively. I System.Timers. When I try high values for timer such as 1 second = (1000ms), it works good but when I try low values it cant work.

To show what the problem is I used a code as you see below:

Timer stopWatchTimer = new Timer();

int timerCounter = 0;

// this method called in button
private void StartStopWatch()
{
    stopWatchTimer.Interval = 1;
    stopWatchTimer.Elapsed += new ElapsedEventHandler(stopWatchTimerElapsed);
    stopWatchTimer.Enabled = true;
}

private void stopWatchTimerElapsed(object sender, ElapsedEventArgs e)
{
    timerCounter++;

    Action a = () =>
    {
        // this is a Label
        lblCounter.Content = timerCounter;
    };

    lblCounter.Dispatcher.Invoke(a);

    if(timerCounter == 200)
    {
        stopWatchTimer.Enabled = false;
    }
}

for example I use a Label and set my interval to 200 ms. So my timer should be stopped less than 1 second (1/5 second) but it takes too long. where is the problem?

Babak.Abad
  • 2,839
  • 10
  • 40
  • 74
  • Probably everywhere. Update the timerCounter in your timer elapsed thread. Then add a DispatcherTimer that updates the UI. Don't do both. That way you won't have to worry about being in sync as whenever the dispatcher timer executes you'll have the current value of your timer counter. –  May 18 '15 at 16:47
  • What are you trying to accomplish? – George Mamaladze May 18 '15 at 16:48

4 Answers4

1

The interval of your timer is set to 1ms. Windows timers do not have that level of accuracy. Windows timers generally have an accuracy of a little over 8ms in the best case, which means your timer firing will be off anywhere between +-4 ms or more. I generally try to keep my timers at about 100ms max and use other means of measuring the ellapsed time that are more accurate (Stopwatch) to increment my timing accumulator.

Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76
0

https://msdn.microsoft.com/en-us/library/system.timers.timer.interval%28v=vs.110%29.aspx

You use the Interval property to determine the frequency at which the Elapsed event is fired. Because the Timer class depends on the system clock, it has the same resolution as the system clock. This means that the Elapsed event will fire at an interval defined by the resolution of the system clock if the Interval property is less than the resolution of the system clock. The following example sets the Interval property to 5 milliseconds. When run on a Windows 7 system whose system clock has a resolution of approximately 15 milliseconds, the event fires approximately every 15 milliseconds rather than every 5 milliseconds.

glenebob
  • 1,943
  • 11
  • 11
0

I made more accurate timer depends on system tick count.

using System;
using System.ComponentModel;

namespace Timers
{
    public class HandmadeTimer
    {
        private int interval = 100;
        private bool enabled = false;
        private BackgroundWorker BGW = new BackgroundWorker();

        public HandmadeTimer(int interval)
        {
            this.interval = interval;
            this.enabled = false;
            this.BGW.WorkerSupportsCancellation = true;
            this.BGW.DoWork += BGW_DoWork;
            this.BGW.WorkerReportsProgress = true;
            this.BGW.ProgressChanged += BGW_ProgressChanged;
        }

        public void Start()
        {
            if (!(enabled))
            {
                enabled = true;
                BGW.RunWorkerAsync();
                StartedEventHandler handler = Started;
                if (!(handler == null))
                    handler();
            }
        }

        public void Stop()
        {
            if (enabled)
            {
                enabled = false;
                BGW.CancelAsync();
                StoppedEventHandler handler = Stopped;
                if (!(handler == null))
                    handler();
            }
        }

        public bool Enabled
        {
            get { return this.enabled; }
            set { if (value)  Start(); else Stop(); }
        }

        public int Interval
        {
            get { return this.interval; }
            set { if (value > 0) this.interval = value; }
        }

        private void BGW_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            long counter = Environment.TickCount + this.interval;
            do
            {
                if (counter <= Environment.TickCount)
                {
                    BGW.ReportProgress(100);
                    counter += this.interval;
                }
            } while (this.enabled);
        }

        private void BGW_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            ElapsedEventHandler handler = Elapsed;
            if (!(handler == null))
                handler();
        }

        public delegate void ElapsedEventHandler();
        public event ElapsedEventHandler Elapsed;
        public delegate void StartedEventHandler();
        public event StartedEventHandler Started;
        public delegate void StoppedEventHandler();
        public event StoppedEventHandler Stopped;
    }
}

More efficient, more accurate, and for free :P

I hope it helps!

Aly Elhaddad
  • 1,913
  • 1
  • 15
  • 31
0

use DispatcherTimer instead of timer

DispatcherTimer myTimer = new DispatcherTimer();
myTimer.Interval = TimeSpan.FromMilliseconds(1);
myTimer.Tick += myTimer_Tick;

so every thing in myTimer_Tick should be done every 1ms.

  • be aware that if you put heavy calculation in myTimer_Tick the interval will not be accurate.
  • also be aware that if the computer is busy, it will generate soeme timer delays too, but you can play with the DispatcherPriority to get your timer executes first.