我有一个函数(比如foo()
),它会不时以可变间隔调用。当它被调用时,它会检查时间并相应地采取行动。
我已通过以下方式完成此操作:
Forms.Timer
对象在需要时调用该函数
在函数中使用Diagnostics.Stopwatch
对象来确定时间和决定做什么。
但是我有以下问题:当Timer的回调调用foo()
时,秒表对象的ElapsedMilliseconds
值通常低于预期值。例如,计时器设置为1000,因此在调用1000毫秒后foo()
,但在foo()
正文ElapsedMilliseconds
内返回900,因此foo
的行为就好像经过的时间是900(虽然它应该采取行动A,因为实际上已经过了1000毫秒,但它没有)
在ElapsedMilliseconds与计时器具有一致值的情况下,如何同步计时器和秒表?
编辑:部分代码
一些示例代码解释了我的问题:
//foo is the function that is called by timer's callback
public void foo()
{
//Let's see what time it is:
long currentTime = stopwatch.ElapsedMilliseconds();
Item = getCurrentItem(currentTime);
Item.Draw();
}
//this is the callback of timer
private void timer1_Tick(object sender, EventArgs e)
{
//set the timer for next time
timer1.Interval = Intervals[periodIdx++];
foo();
}
这应该在每次间隔完成时绘制其他内容,但是因为ElapsedMilliseconds
返回的值早于计时器声明,尽管间隔结束,但未绘制下一个项目
答案 0 :(得分:3)
你得到了很大的不同,因为你在1/64秒间隔内的某个地方启动计时器。你会得到更好的结果:
private void StartTimers() {
int tick = Environment.TickCount;
while (Environment.TickCount == tick) Thread.Sleep(0);
timer1.Enabled = true;
stopwatch.Start();
}
while()循环改善了计时器在1/64计时器开始时启动的几率。只是提高,没有保证。而且你不能对Tick事件发送起来做任何事情,它完全取决于你的UI线程的响应能力。但总是迟到。不要使用此代码,编写代码,这样您就不必关心这些定时器不同步。您可能必须减少计时器的间隔才能实现这一点,但问题并不明确。
答案 1 :(得分:2)
这种方法不会取得太大成功。您没有在同一时间启动每个计时器,并且您没有在同一时间检查它们(计时器触发它的事件和您的代码查询秒表之间有一段时间)。
如果您想要同步,请选择一个计时器,并将所有内容基于它。例如,如果你想使用Forms.Timer,在它的事件处理程序中只需增加一个计数器变量 - 它将告诉你调用处理程序的次数,有效地,Forms.Timer说了多少时间已经过去了。这是一个例子(我将留给你处理计时器滴答的时间足够长,计数器超过long.MaxValue)
public void foo()
{
Item = getCurrentItem(totalElapsed);
Item.Draw();
}
long totalElapsed = 0;
private void timer1_Tick(object sender, EventArgs e)
{
totalElapsed += timer1.Interval;
//set the timer for next time
timer1.Interval = Intervals[periodIdx++];
foo();
}