如何在C#中重置计时器?

134

我知道有三个与Timer相关的类:System.Threading.TimerSystem.Timers.TimerSystem.Windows.Forms.Timer,但是它们都没有一个.Reset()函数,可以将当前经过的时间重置为0。

是否有BCL类具备此功能呢?是否有非hack方式实现此功能呢?(我认为也许改变时间限制可能会重置它)是否考虑重新实现一个带有此功能的Timer类,或者如何在BCL类之一中可靠地实现此功能?


3
使用JP的解决方案,使用扩展方法实现。 - benPearce
我也有重置的同样需求,原因与提到的相同,FileSystemWatcher 使用起来很不方便。 - John Lewin
如果您使用Stopwatch作为计时器并选择使用扩展方法答案,请注意,因为Stopwatch.Restart扩展方法将在.NET 4.0中推出。http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.restart(VS.100,lightweight).aspx - si618
11个回答

174

我经常使用以下代码来获取当前脚本的文件名:

myTimer.Stop();
myTimer.Start();

...那算不算是一个技巧呢? :)

根据评论,在Threading.Timer中,这是Change方法...

dueTime 类型:System.Int32 在以毫秒为单位构造 Timer 时指定的回调方法被调用之前要延迟的时间量。指定 Timeout.Infinite 以防止计时器重新启动。将其指定为零 (0) 以立即重新启动计时器。


另一个问题是它只能与Forms.Timer一起使用,而我的应用程序没有GUI(没有参数的Application.Start()),所以我认为Threading.Timer类在其他方面更好,但这也是个好观点。 - Matthew Scharley
3
@Matthew:请参考http://msdn.microsoft.com/en-us/magazine/cc164015.aspx,了解各种计时器类及其适用情况。一般来说,“Forms.Timer”只能用于GUI。但是,除了“Forms.Timer”和“Threading.Timer”之外,还有“Timers.Timer”。 - Brian

70

除了System.Threading.Timer之外,所有计时器都具有Start()和Stop()方法的相当版本。

因此,可以使用扩展方法...

public static void Reset(this Timer timer)
{
  timer.Stop();
  timer.Start();
}

这是一种可行的方法。


2
我不是在寻找测量经过时间的方法。我的确切用例是,我有一个FileSystemWatcher监视一个目录,并希望捕获一组更改(即,在彼此之间例如5秒内进行的更改)。理论上,第一次更改启动计时器,每次更改都会重置它,直到最终触发并关闭该组。 - Matthew Scharley
是的,当我重新阅读你的问题时,我注意到了这一点。已经编辑了我的答案。 - Dan
这个是有效的,需要注意的是如果你只调用 timer.Start() 是不会起作用的。我写了这个Linqpad查询来测试它。试着把其中的 timer.Stop 移除,你就会看到区别。 - Jared Beach

33

对于 System.Timers.Timer,根据 MSDN 文档 http://msdn.microsoft.com/en-us/library/system.timers.timer.enabled.aspx

如果在 Timer 启动之后设置间隔,则计数会被重置。例如,如果您将间隔设置为 5 秒,然后将 Enabled 属性设置为 true,则计数从 Enabled 设置的时间开始。如果您在计数为 3 秒时将间隔重置为 10 秒,则 Elapsed 事件将在启用为 true 的 13 秒后首次引发。

因此,

    const double TIMEOUT = 5000; // milliseconds

    aTimer = new System.Timers.Timer(TIMEOUT);
    aTimer.Start();     // timer start running

    :
    :

    aTimer.Interval = TIMEOUT;  // restart the timer

1
问题在于,你并不总是知道在你想要重置计时器的那一刻,计时器是否已经在运行。因此,你需要执行 aTimer.Interval = TIMEOUT 和 aTimer.Start()。因此,在整个过程中,上面的重置函数使用了更少的行和变量。虽然这是一个很好的补充。 - e-motiv
我也遇到过这样的问题。我的解决方法是:aTimer.Interval = aTimer.Interval。这会触发循环继续执行。不知道为什么,但它确实有效... - Herman Van Der Blom

8

你可以编写一个名为Reset()的扩展方法,它可以:

  • 对于Timers.Timer和Forms.Timer,调用Stop()-Start()
  • 对于Threading.Timer,调用Change

4

我刚刚给计时器分配了一个新值:

mytimer.Change(10000, 0); // 重置为10秒

对我来说它运行得很好。

在代码顶部定义计时器:System.Threading.Timer myTimer;

if (!active)
    myTimer = new Timer(new TimerCallback(TimerProc));

myTimer.Change(10000, 0);
active = true;

private void TimerProc(object state)
{
    // The state object is the Timer object.
    var t = (Timer)state;

    t.Dispose();
    Console.WriteLine("The timer callback executes.");
    active = false;
    
    // Action to do when timer is back to zero
}

3
你可以执行 timer.Interval = timer.Interval

3

对于计时器(System.Windows.Forms.Timer)。

.Stop,然后 .Start 方法可作为重置使用。


1
我会做以下事情。 处理计时器并重新初始化它。 但这将擦除您附加到此计时器的任何事件。
timer.Dispose();
timer = new System.Timers.Timer();

0

很抱歉回答晚了,但希望这个回答能对你有所帮助。 如果你需要一个“看门狗”式的计时器,可以使用System.Threading.Timer类和Change方法。

以下是一段代码片段,它将只在用户没有中断操作超过3秒钟时调用test方法:

using System;
using System.Threading;
namespace WatchdogExample
{
    internal class Watchdog
    {
        static void Main(string[] args)
        {
            Timer t = new Timer(timer_callback, null, 3000, Timeout.Infinite);
            while (true)
            {
                Console.ReadLine();
                t.Change(3000, Timeout.Infinite);
            }
        }
        static void timer_callback(object state)
        {
            Console.WriteLine("test");
        }
    }
}

0

重置Windows计时器的另一种替代方法是使用计数器,具体如下:

int timerCtr = 0;
Timer mTimer;

private void ResetTimer() => timerCtr = 0;
private void mTimer_Tick()
{
    timerCtr++;
    // Perform task
}  

所以如果您想要每1秒重复一次,您可以将定时器间隔设置为100毫秒,并测试计数器进行10个周期。

如果定时器应等待某些在不同时间跨度结束的进程,则此方法非常适用。


1
我甚至不知道 ctr 是什么。我猜它是 counter,但即使如此,我也不知道它应该意味着什么。它是在计算滴答声的数量还是其他什么? - AustinWBryan
是的,谢谢你尝试编辑,但答案让我感到困惑,我完全不明白@ivan想做什么。 - IARI

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接