I have a basic question regarding timers. My timer is acting very strange. I am trying to make the tick occur every millisecond to update my data. I can get it to work with seconds, it seems, but not milliseconds..
I am using WPF and am wondering why the following is not functioning correctly.
It appears that the "second" countdown works correctly, but while using the same procedure and editing one value, it does not "tick" correctly it seems.
I am trying to make a millisecond countdown using the following:
//TimeSpan temp0 = new TimeSpan(0, 0, 0, 0, 1);
CountdownTimer = new DispatcherTimer();
CountdownTimer.Tick += new EventHandler(Countdowntimer_Tick);
CountdownTimer.Interval = TimeSpan.FromSeconds(1.0);//temp0;
The above seems like it works fine for a "second" countdown, but I need more precision, so I do the following:
//TimeSpan temp0 = new TimeSpan(0, 0, 0, 0, 1);
IntroCountdownTimer = new DispatcherTimer();
IntroCountdownTimer.Tick += new EventHandler(Countdowntimer_Tick);
IntroCountdownTimer.Interval = TimeSpan.FromSeconds(0.001);//temp0;
This would give us millisecond precision, BUT, when I try this in my program, it is much much slower. Any ideas why?
void Countdowntimer_Tick(object sender, EventArgs e)
{
m_dIntroCountdown -= 1.0;
}
ps: I do set the "m_dIntroCountdown accordingly. If we are in milliseconds, I set it to 5000.0, if in seconds, 5.0
Maybe I am looking too much into this.. any ideas?
All help is appreciated.
Thanks!
What do you want the resolution for? If you are just trying to keep track of time, use System.Diagnostics.Stopwatch. It has ~10ns resolution.
A 1 ms time resolution is way too fine for what WPF can handle. Even at 120 fps (which is high), you will only get 8.3 ms resolution. In order to update at 1ms, you'd need to render 1000 frames per second. This is just beyond the limits of any modern system. Even the human eye starts to lose track of discontinuous changes in motion at ~10ms.
This is the code for C#:
using System.Windows.Threading;
public partial class MainWindow
{
DateTime Time = new DateTime();
DispatcherTimer timer1 = new DispatcherTimer();
private void dispatchertimer_Tick(object sender, EventArgs e)
{
TimeSpan Difference = DateTime.Now.Subtract(Time);
Label1.Content = Difference.Milliseconds.ToString();
Label2.Content = Difference.Seconds.ToString();
Label3.Content = Difference.Minutes.ToString();
}
private void Button1_Click(System.Object sender, System.Windows.RoutedEventArgs e)
{
timer1.Tick += new System.EventHandler(dispatchertimer_Tick);
timer1.Interval = new TimeSpan(0, 0, 0);
if (timer1.IsEnabled == true)
{
timer1.Stop();
}
else
{
Time = DateTime.Now;
timer1.Start();
}
}
Here is how to do it:
Add 3 labels and 1 button : Label1, Label2, Label3 and Button1
This is the code for Vb(Visual Basic):
Imports System.Windows.Threading
Class MainWindow
Dim timer1 As DispatcherTimer = New DispatcherTimer()
Dim Time As New DateTime
Private Sub dispatchertimer_Tick(ByVal sender As Object, ByVal e As EventArgs)
Dim Difference As TimeSpan = DateTime.Now.Subtract(Time)
Label1.Content = Difference.Milliseconds.ToString
Label2.Content = Difference.Seconds.ToString
Label3.Content = Difference.Minutes.ToString
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
AddHandler timer1.Tick, AddressOf dispatchertimer_Tick
timer1.Interval = New TimeSpan(0, 0, 0)
If timer1.IsEnabled = True Then
timer1.Stop()
Else
Time = DateTime.Now
timer1.Start()
End If
End Sub
End Class
DispatcherTimer is not an high precision timer - it's a low precision low accuracy timer suitable for UI work (where people don't notice delays of 100ms).
A high precision timers that execute code every 1ms is very difficult, maybe even impossible, to implement (what do you do if some other process in the system goes to 100% CPU and your process doesn't run for over 1ms? what do you do if the code executed by the time has to be reloaded from the page file and it takes more than 1ms?).
Related
I'm using a DispatcherTimer to call a void in C#:
counter = new System.Windows.Threading.DispatcherTimer();
counter.Tick += new EventHandler(counter_Tick);
counter.Interval = new TimeSpan(0, 0, 1);
counter.Start();
However I would like the interval to be a few milliseconds, TimeSpan's parameters are hours,minutes,seconds and only accepts integers (as far as I can see). Is there a work around for DispatcherTimer? I've tried Timer but I cannot use it (missing reference apparently)
Thanks in advance.
Another way
counter.Interval = TimeSpan.FromMilliseconds(1);
The TimeSpan object has a constructor that takes milliseconds as a parameter:
MSDN has the details: https://msdn.microsoft.com/en-us/library/6c7z43tw(v=vs.110).aspx
Basically, replace new TimeSpan(0, 0, 1) with new TimeSpan(0, 0, 0, 0, millisecondTimeout).
Although #EBrown's answer already tells you how to use milliseconds with a DispatcherTimer, its precision is supposedly around 15-20 ms, and the errors add up at each iteration, which makes it a bit impractical.
However it is possible to work around this issue by starting a System.Diagnostics.StopWatch at the same time as the DispatcherTimer and checking the StopWatch.ElapsedMilliseconds inside the Tick Event with a smaller time step, and that seems to give more precise results. It also works with a System.Timers.Timer.
Here's a short example based on a WPF program I made.
private void StartTimers(object sender, RoutedEventArgs e)
{
dtimer = new DispatcherTimer();
dtimer.Tick += new EventHandler(dTimer_Tick);
dtimer.Interval = TimeSpan.FromMilliseconds(1); // the small time step
stopWatch = new StopWatch();
dTimer.Start();
stopWatch.Start();
}
private void dTimer_Tick(object sender, EventArgs e)
{
currentTime = stopWatch.ElapsedMilliseconds;
if (currentTime - oldTime > interval)
{
oldTime = currentTime;
DoStuff();
}
}
Using StopWatch.Restart in the Tick Event to do iterations will have the same error problem the DispatchTimer causes, because it's going to restart when the DispatchTimer event is fired.
I am working on my app for Windows Phone 8
and i created a DispatcherTimer
DispatcherTimer Timer= new DispatcherTimer();
private int TimePass;
public TapFast()
{
TimePass = 0;
Timer.Tick += new EventHandler(TimePassTick);
Timer.Interval = TimeSpan.FromMilliseconds(1);
InitializeComponent();
}
public void TimePassTick(Object sender, EventArgs args)
{
TimePass++;
TimeSpan t = TimeSpan.FromMilliseconds(TimePass);
string answer = string.Format("{0:D2}h:{1:D2}m:{2:D2}s:{3:D4}ms",
t.Hours,
t.Minutes,
t.Seconds,
t.Milliseconds);
time.Text = answer;
}
When i start the timer , i don't get the right result in the TextBlock
1 second = 1000 milliseconds
I must see a value of 0 increases to 1000 in 1 second
but it takes like 18-20 seconds to get to 1000ms
what is the problem ?
Windows and the associated APIs are not "real time". Your timer interval is so small that there's no way for Windows to service it on the schedule you're asking for.
With non-real-time OS and APIs, you can't assume that the timer is actually signaled on exactly the interval you asked for. You need to keep track of the actual time yourself (e.g. using the System.Diagnostics.Stopwatch class) and accommodate variations you experience.
This is my second question on StackOverflow here. I posted my first question a while ago and got a working reply in no time, much impressed, much appreciated.
Anyways, so what I want to know is, how to get a DispatcherTimer to work and show time in a certain textbox and stop it when it reaches a certain time (let's say 60 seconds) and perform a function after 60 seconds.
What I'm basically using this for is :
Making a game, which has to stop after 60 seconds and show the scores or related stuff. So this requires me to show the time in a textbox and perform a function at 60 seconds or after that.
Here's more information :
Textbox is called "timerbox"
Here's the code I've tried :
DispatcherTimer dt = new DispatcherTimer();
private void TimerStart(object sender, RoutedEventArgs e)
{
dt.Interval = TimeSpan.FromSeconds(1);
dt.Tick += dt_Tick;
dt.Start();
}
int count = 0;
void dt_Tick(object sender, object e)
{
count = count + 1;
timerbox.Text = Convert.ToString(count);
}
It doesn't show the time in textbox, plus I don't know how to make it stop at certain point and perform a function.
Thank you for reaching here, please leave answers with full explanation as I'm a complete beginner :)
P.S. I'm using Windows Store App Development Environment in Visual Studio 2013.
And there's no "Timer" in it as there is in normal C# Environment.
AOA.
I am recently started learning c#. (interested in windows form application). Hope this help you.
if you just want to set timer for a curtain event.....
recommend you using timer ( in toolbox )......
follow steps, when you double click on timer1 VS will create a timer1_Tick function for you which will be called every timer you timer ticks.....
now what you want to do when timer1 icks write it in there....like this....
private void timer1_Tick(object sender, EventArgs e)
{
//enter your code here
}
now write timer1. and VS will display a list of avaliable function....
for example,
timer1.Interval = (60*1000); //enter time in milliseconds
now when you want to start the write......
timer1.Start();
and to stop timer at any timer call
timer1.Stop();
if you want to repeat timer just write timer1.start() in that tick function.....
plus, to set textbox text equal to timer1 time use something like
textBox1.Text = Convert.ToString(timer1.Interval);
Click here for more information on timer class
hope this help you,
in case of any confusion, just comment,.....
The normal flow of a DispatcherTimer would look like this:
First Set up your new Object, set up the a new EventHandler that will run your desired code each Tick and Set the Timespan for the desired Tick Interval.
public MainPage()
{
this.InitializeComponent();
timer = new DispatcherTimer();
timer.Tick += new EventHandler<object>(timer_Tick);
timer.Interval = TimeSpan.FromMilliseconds(bpm);
}
Set The Timer_Tick Envent
async Void timer_Tick(object Sender, object e)
{
await this.Dispatcher.RunAsync(Windows.UI.core.CoreDispatcherPriority.High, () =>
{
//Run the Code
textBox1.text = timer.interval.TotalMilliseconds.ToString();
});
You have to have a trigger to Start the Dispatcher(and to stop if you need to), for example a button
private void StartButton_Click()
{
timer.Start();
}
This example was done using The new windows 10 Universal App platform within VS2015, but I think it should look about the same in a normal windows 8 App
I am trying to get a timer run every minute in sync with the system clock (00:01:00, 00:02:00, 00:03:00, etc). This is my code.
private System.Timers.Timer timer;
public frmMain()
{
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = GetInterval();
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString("hh:mm:ss tt"));
timer.Interval = GetInterval();
timer.Start();
}
private double GetInterval()
{
DateTime now = DateTime.Now;
return ((60 - now.Second) * 1000 - now.Millisecond);
}
It runs perfectly on my home PC.
12:12:00 AM
12:13:00 AM
12:14:00 AM
12:15:00 AM
12:16:00 AM
12:17:00 AM
12:18:00 AM
12:19:00 AM
12:20:00 AM
12:21:00 AM
However I'm getting weird results on my VPS (windows server 2003).
12:11:59 AM
12:12:59 AM
12:13:00 AM
12:13:59 AM
12:14:00 AM
12:14:59 AM
12:15:00 AM
12:15:59 AM
12:16:00 AM
12:16:59 AM
12:17:00 AM
12:17:59 AM
12:18:00 AM
12:18:59 AM
12:19:00 AM
12:19:59 AM
12:20:00 AM
12:20:59 AM
12:21:00 AM
Is it because System.Timers.Timer does not work well on windows server 2003? Or is it an issue with my VPS?
Instead of using DateTime.Now and pulling the individual parts, just use the Ticks. Get the ticks when you start, then calculate what the ticks should be for the next timer tick. Once that timer tick occurs use the last value to calculate what the next value should be.
Example:
private const long MILLISECOND_IN_MINUTE = 60 * 1000;
private const long TICKS_IN_MILLISECOND = 10000;
private const long TICKS_IN_MINUTE = MILLISECOND_IN_MINUTE * TICKS_IN_MILLISECOND;
private System.Timers.Timer timer;
private long nextIntervalTick;
public void frmMain()
{
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = GetInitialInterval();
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
System.Diagnostics.Trace.WriteLine(DateTime.Now.ToString("hh:mm:ss tt"));
timer.Interval = GetInterval();
timer.Start();
}
private double GetInitialInterval()
{
DateTime now = DateTime.Now;
double timeToNextMin = ((60 - now.Second) * 1000 - now.Millisecond) + 15;
nextIntervalTick = now.Ticks + ((long)timeToNextMin * TICKS_IN_MILLISECOND);
return timeToNextMin;
}
private double GetInterval()
{
nextIntervalTick += TICKS_IN_MINUTE;
return TicksToMs(nextIntervalTick - DateTime.Now.Ticks);
}
private double TicksToMs(long ticks)
{
return (double)(ticks / TICKS_IN_MILLISECOND);
}
You could probably do this using Seconds and Milliseconds like you were. The trick is to have one starting point to calculate off of (rather then determining how many seconds to the next minute). If there are additional concerns not mentioned in the original problem, like the code in timer_Elapsed might take longer then a minute to run, then you will need to add code to handle this.
Please leave a comment if you need additional help. Otherwise please select a correct answer.
((60 - now.Second) * 1000 - now.Millisecond)
This means that if now.Second happens to be 59 your time will fire again in less than a second. This is the reason for your weird results (the timer not firing at exactly 0 second offsets).
It's probably more productive for you to have the timer fire every second, keep the previous date/time value in a separate variable, and update the on-screen timer when the second portion changes.
Normal timers like System.Timers.Timer are not accurate and not nearly good enough to achieve a 1 msec interval.
Firstly they have an internal update rate of 10-15 msec. Secondly depending on the system other threads may run for ~15 msec delaying your timer before Windows forces them to yield.
If you want more accuracy than Timer use System.Diagnostics.Stopwatch as reported in another thread it can go from 0.3 ms and is integrated with your .NET environment.
Another option is to use a multimedia time (accurate to around 1ms).
Either way here is an excellent tutorial on the issue.
Breaking it down:
Timer drift normally adds a delay to the timer. But you are seeing the opposite happen. As timers do not have millisecond accuracy (they are only accurate to in the 15ms range) they will often be fired with that granularity. So in effect firing the timer a few milliseconds before the minute mark on some occasions (causing it to fire immediately afterwards aswell). If you require it to only fire in the new minute I would add in a few milliseconds of a wait time to compensate (5ms should do it).
Your home pc is not so fast (which means it exhibits extra timer drift dealing with the timer handler) and normally fires the event in the next second. Your work PC sometimes manages to handle the timer event quick enough that it records 59 seconds past (which I do believe is truncated and probably 59.900 ~ 59.999). This may also occur if the machine is multi-cored as there is no thread yeilding delay and the timer can be fired very quickly.
That is the cause of your Timer irregularities.
Hi another example is use the Timer from System.Windows.Threading.
using System;
using System.Windows.Threading;
namespace Yournamespace
{
public partial class TestTimer
{
DispatcherTimer dispatcherTimer1m;
public TestTimer()
{
dispatcherTimer1m = new DispatcherTimer();
dispatcherTimer1m.Tick += new EventHandler(DispatcherTimer1m_Tick);
dispatcherTimer1m.Interval = TaskHelper.GetSyncIntervalms;
dispatcherTimerm.Start();
}
private void DispatcherTimer1m_Tick(object sender, EventArgs e)
{
try
{
dispatcherTimer1m.Stop();
//Do your effort here
}
catch (Exception exc)
{
//Your exception handled here
}
finally
{
dispatcherTimer1m.Interval = TaskHelper.GetSyncInterval1m;
dispatcherTimer1m.Start();
}
}
}
public class TaskHelper
{
private const ushort internalUpdate = 15;//ms
public static TimeSpan GetSyncInterval1m => new TimeSpan(0, 0, 0, 60,internalUpdate).Subtract( new TimeSpan(0, 0, 0, DateTime.Now.Second, 0));
}
}
Remember that Windows Server is by default set up to share resources with background tasks more willingly than the client versions so timer accuracy can be affected if the server is running a number of background tasks.
You could try temporarily changing it to prioritise the foreground task to see if that gives different results - the setting is somewhere in the System control panel, you're looking for two radio buttons, one that says "Programs" and one that says "Background services" or similar.
I want to disable a button -to prevent double click: On a tablet PC you push once, it clicked twice and this is the easiest hack that I know- for a short period but I noticed/debugged the interval might be too long in practice; 50 ms vs > 2 seconds.
There is in only one line starts the timer and one line stops it. Randomly the interval is 50 ms or much bigger. There is no CPU consume, I just click the button with mouse on my 4 core desktop PC.
What would be the reason?
DispatcherTimer timerTouchDelay = new DispatcherTimer();
protected override void OnMouseDown(MouseButtonEventArgs e)
{
//Init
if (timerTouchDelay.Interval.Milliseconds == 0)
{
timerTouchDelay.Tick += new EventHandler(timerTouchDelay_Tick);
timerTouchDelay.Interval = new TimeSpan(0, 0, 0, 0, 50); //ms
}
if(timerTouchDelay.IsEnabled)
return;
timerTouchDelay.Start();
HandleKeyDown();
base.OnMouseDown(e);
}
private void timerTouchDelay_Tick(object sender, EventArgs e)
{
timerTouchDelay.Stop();
}
To understand why this is the case, I would highly recommend the following article:
Comparing the Timer Classes in the .NET Framework Class Library
For reference, DispatcherTimer is very similar to System.Windows.Forms.Timer, for which the author states "If you're looking for a metronome, you've come to the wrong place". This timer is not designed to 'tick' at exact intervals.
Instead of running a timer, why not just record the time at which the button was last pressed. If it's more than 50 milliseconds ago, go ahead and perform the action, otherwise just exit.
DateTime lastMouseDown = DateTime.MinValue;
protected override void OnMouseDown(MouseButtonEventArgs e)
{
if(DateTime.Now.Subtract(lastMouseDown).TotalMilliseconds < 50)
return;
lastMouseDown = DateTime.Now;
HandleKeyDown();
base.OnMouseDown(e);
}