如何使用计时器等待?

我试图通过使用计时器延迟我的方法中的事件,但我不一定了解如何使用计时器等待。

我将我的计时器设置为2秒,但是当我运行此代码时,最后一次调用运行没有2秒延迟。

Timer timer = new Timer(); timer.Tick += new EventHandler(timer_Tick); // Everytime timer ticks, timer_Tick will be called timer.Interval = (1000) * (2); // Timer will tick evert second timer.Enabled = true; // Enable the timer void timer_Tick(object sender, EventArgs e) { timer.Stop(); } private void button1_Click(object sender, EventArgs e) { label1.Text = "first"; timer.Start(); label1.Text = "second"; } 

因此,当我单击我的按钮时,它会立即将label1显示为“second”,而不是更改为“first”,等待2秒,然后更改为“second”。 我在这里读了很多关于使用计时器而不是thread.sleep的线程,但我似乎无法找到/弄清楚如何实际实现它。

timer.Start()只是启动计时器,但在计时器在后台运行时立即返回。 因此,在将标签文本设置为firstsecond之间几乎没有停顿。 你想要做的是等待定时器勾选,然后再次更新标签:

 void timer_Tick(object sender, EventArgs e) { timer.Stop(); label1.Text = "second"; } private void button1_Click(object sender, EventArgs e) { label1.Text = "first"; timer.Start(); } 

顺便说一句。 你不应该将timer.Enabled设置为true,你已经使用timer.Start()启动了计时器。

正如评论中所提到的,您可以将计时器创建放入一个方法,如下所示(注意:这是未经测试的):

 public void Delayed(int delay, Action action) { Timer timer = new Timer(); timer.Interval = delay; timer.Tick += (s, e) => { action(); timer.Stop(); }; timer.Start(); } 

然后你可以像这样使用它:

 private void button1_Click(object sender, EventArgs e) { label1.Text = "first"; Delayed(2000, () => label1.Text = "second"); } 

Tergiver的后续行动

使用Delayed是否包含内存泄漏(引用泄漏)?

订阅事件始终会创建双向引用。

在这种情况下, timer.Tick获取对匿名函数(lambda)的引用。 该函数提升了一个局部变量timer ,虽然它是一个引用,而不是一个值,并且包含对传入的Action委托的引用。 该委托将包含对label1的引用, label1Form的实例成员。 那么从TimerForm有一个循环引用吗?

我不知道答案,我发现它有点难以推理。 因为我不知道,我会删除在Delayed使用lambda,使其成为一个正确的方法并拥有它,除了停止计时器(这是方法的sender参数)之外,还删除事件。

通常lambdas不会导致垃圾回收问题。 在这种情况下,计时器实例仅存在于本地,并且lambda中的引用不会阻止垃圾收集来收集实例(另请参阅此问题 )。

我实际上使用.NET Memory Profiler再次测试了这个。 收集的计时器对象很好,没有发生泄漏。 分析器确实给了我一个警告,即有些情况“虽然没有妥善处理,但已经收集了垃圾”。 删除事件处理程序本身(通过保持对它的引用)并没有解决这个问题。 将捕获的定时器参考更改为(Timer)s也没有改变。

什么帮助 – 显然是 – 在停止计时器后调用事件处理程序中的timer.Dispose() ,但我认为这是否真的有必要。 我不认为分析器警告/注释是关键的。

如果你正在使用C#5.0 await ,那么这将更容易:

 private async void button1_Click(object sender, EventArgs e) { label1.Text = "first"; await Task.Delay(2000); label1.Text = "second"; } 

如果您要做的只是在计时器滴答时更改文本,那么你最好不要放……

 label1.Text = "second"; 

…在计时器滴答中,在将计时器更改为enabled = false之前或之后;

像这样;

 void timer_Tick(object sender, EventArgs e) { timer.Stop(); label1.Text = "second"; } private void button1_Click(object sender, EventArgs e) { label1.Text = "first"; timer.Start(); } 
  private bool Delay(int millisecond) { Stopwatch sw = new Stopwatch(); sw.Start(); bool flag = false; while (!flag) { if (sw.ElapsedMilliseconds > millisecond) { flag = true; } } sw.Stop(); return true; } bool del = Delay(1000);