Here is the scenario:
There is a Textbox
in which a user enters the time at which the DispatcherTimer
must start. The Timer is set to run for 4 hours always and Timer.Tick event plays a sound. Let's say the timer starts at 04:00:00 (HH:mm:ss), it should run till 8:00:00 and then stop. Then when the user changes the time, let's say, to 09:00:00. The timer should run till 13:00:00 and so on.
How can this be achieved? I can't run a 1 minute timer that keeps checking for the right time because that will be very heavy on the system.
All help is appreciated. Thank you in advance.
Just like with the timer, you can start a stopwatch right from Google's homepage. To do it, just type 'Start a stopwatch' in the search bar. Once it's running, you can start, stop, and restart the stopwatch.
The method below starts an initial timer with an interval based on the datetime supplied (i.e. the time entered into your textbox). When the the time is reached it starts a secondary timer that will fire every four hours from that point on.
I used System.Timers Timer rather than the Sytem.Threading Timer (because ironically the system.threading timer is not thread safe!)
public void StartTimer(DateTime time)
{
const int fourHoursInMilliseconds = 4 * 3600 * 1000;
var fourHourTimer = new Timer() {Interval = fourHoursInMilliseconds};
fourHourTimer.Elapsed += (sender, e) =>
{
//code to handle the elapsed event here
};
var span = time - DateTime.Now;
var timer = new Timer {Interval = span.TotalMilliseconds, AutoReset = false};
timer.Elapsed += (sender, e) => { fourHourTimer.Start();};
timer.Start();
}
Hope this is what you need.
You have 2 problems here.
Scheduling (assuming your software will be running) is basically creating timer when user finishes his input. If user changes time you have to stop that timer and start it again using new time.
Regarding re-evaluating, same tactic: create and start new timer every time user change value, taking in account whenever timer is running and already passed time.
So basically it will be 2 timers, where one is used to start another.
Pseudocode:
DispatcherTimer _scheduler;
DispatcherTimer _timer;
DateTime _start;
TimeSpan _duration;
// call this when specified time is changed
void Schedule(DateTime time)
{
_start = time;
// prevent any logic to run if timer is counting duration
if(_timer != null)
return;
// stop scheduler
if(_scheduler != null)
_scheduler.Stop();
// create new scheduler
_scheduler = new DispatcherTimer { Interval = _start - DateTime.Now };
_scheduler.Tick = (s, e) =>
{
Start(_duration); // here scheduler will start timer
_scheduler.Stop(); // after that you don't need scheduler anymore
_scheduler = null;
}
_scheduler.Start();
}
// call this when duration is changed
void Start(TimeSpan duration)
{
_duration = duration;
// prevent from running before starting time
if(DateTime.Now < _start)
return;
// stop running timer
if(_timer != null)
_timer.Stop();
// create timer to count duration including already expired time
_timer = new DispatcherTimer { Interval = _duration - (DateTime.Now - _start) };
_timer.Tick = (s, e) =>
{
... // whatever
_timer.Stop(); // clean up
_timer = null;
}
_timer.Start();
}
I am using DispatcherTimer
to avoid invoke when starting another DispatcherTimer
. Both Schedule()
and Start()
should be called from UI thread (e.g. TextChanged
event handler).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With