我试图用一个定时器,以延迟在我的方法的事件,但是我并不知道如何使用定时器等待。
设置我的计时器为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的“第二”,而不是更改为“第一”,等待2秒钟,然后切换到“秒”。 我已经阅读了大量的线程在这里有关使用定时器来代替了Thread.Sleep,但我似乎无法找到/弄清楚如何真正实现这一点。
timer.Start()
刚刚启动计时器,但同时计时器在后台运行立即返回。 因此,设置标签文本之间的first
和second
有几乎没有停顿。 你想要做的就是等待计时器滴答作响,然后才再次更新标签:
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的后续
不使用延迟包含内存泄漏(参考泄漏)?
订阅总是一个事件创建一个双向引用。
在这种情况下timer.Tick
获取一个匿名函数(拉姆达)的引用。 这功能提升的局部变量timer
,虽然这是一个参考,而不是一个值,并包含对传入Action委托的参考。 该委托将要包含的引用label1
,所述的一个实例成员Form
。 那么,有没有从循环引用Timer
的Form
?
我不知道答案,我发现它有点难以推论。 因为我不知道,我会删除使用拉姆达的Delayed
,使得它适当的方法和具有它,除了停止定时器(这是sender
方法的参数),还删除事件。
通常lambda表达式不会引起对垃圾回收问题。 在这种情况下,定时器实例仅局部存在,并且在lambda参考并不妨碍垃圾收集,收集实例(也看到了这个问题 )。
我实际测试此再次使用.NET内存分析器。 计时器对象收集就好了,并没有泄漏发生。 探查确实给我一个警告,指出是“[...]已经收集垃圾没有被妥善处理”,尽管情况。 (通过保持对它的引用)删除本身的事件处理程序没有解决,虽然。 改变所捕获的计时器参照(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);