wpf 如何在特定时间在特定时间启动计时器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37656707/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to start a timer at a specific time for a specific time?
提问by thecodrr
Here is the scenario:
这是场景:
There is a Textboxin which a user enters the time at which the DispatcherTimermust 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.
有Textbox一个用户输入DispatcherTimer必须开始的时间。计时器设置为始终运行 4 小时,并且 Timer.Tick 事件播放声音。假设计时器从 04:00:00 (HH:mm:ss) 开始,它应该运行到 8:00:00 然后停止。然后当用户将时间更改为 09:00:00 时。计时器应运行到 13:00:00,依此类推。
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.
如何做到这一点?我无法运行一个 1 分钟的计时器来不断检查正确的时间,因为这会对系统造成很大的负担。
All help is appreciated. Thank you in advance.
感谢所有帮助。先感谢您。
回答by mark_h
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!)
我使用 System.Timers Timer 而不是 Sytem.Threading Timer(因为具有讽刺意味的是 system.threading 计时器不是线程安全的!)
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.
希望这是你所需要的。
回答by Sinatr
You have 2 problems here.
你在这里有两个问题。
- How to start the timer at specified time (this is called scheduling), see e.g. this.
- How to re-evaluatetarget time of possibly running timer.
- 如何在指定时间启动计时器(这称为调度),例如参见this。
- 如何重新评估可能正在运行的计时器的目标时间。
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.
所以基本上它将是 2 个计时器,其中一个用于启动另一个。
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 DispatcherTimerto avoid invoke when starting another DispatcherTimer. Both Schedule()and Start()should be called from UI thread (e.g. TextChangedevent handler).
我DispatcherTimer用来避免在启动另一个DispatcherTimer. 双方Schedule()并Start()应该从UI线程(如被称为TextChanged事件处理程序)。

