如何异步等待x秒然后执行某些操作?

我知道在C#和Windows Forms中有Thread.SleepSystem.Windows.Forms.TimerMonitor.Wait 。 我似乎无法弄清楚如何等待X秒然后做其他事情 – 没有锁定线程。

我有一个带按钮的表格。 在按钮上单击计时器应启动并等待5秒钟。 在这5秒钟后,表格上的其他一些控件显示为绿色。 当使用Thread.Sleep ,整个应用程序将在5秒内无响应 – 所以我如何“在5秒后执行某些操作”?

(由Ben转录为评论)

只需使用System.Windows.Forms.Timer。 将计时器设置为5秒,并处理Tick事件。 当事件发生时,做那件事。

…并在执行oder工作之前禁用计时器(IsEnabled = false)以抑制秒。

Tick事件可能在另一个无法修改你的gui的线程上执行,你可以抓住这个:

 private System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer(); private void StartAsyncTimedWork() { myTimer.Interval = 5000; myTimer.Tick += new EventHandler(myTimer_Tick); myTimer.Start(); } private void myTimer_Tick(object sender, EventArgs e) { if (this.InvokeRequired) { /* Not on UI thread, reenter there... */ this.BeginInvoke(new EventHandler(myTimer_Tick), sender, e); } else { lock (myTimer) { /* only work when this is no reentry while we are already working */ if (this.myTimer.Enabled) { this.myTimer.Stop(); this.doMyDelayedWork(); this.myTimer.Start(); /* optionally restart for periodic work */ } } } } 

只是为了完整性:使用async / await,可以延迟执行非常简单的操作(一次性,不再重复调用):

 private async Task delayedWork() { await Task.Delay(5000); this.doMyDelayedWork(); } //This could be a button click event handler or the like */ private void StartAsyncTimedWork() { Task ignoredAwaitableResult = this.delayedWork(); } 

有关更多信息,请参阅MSDN中的“async和await”。

您可以启动执行操作的异步任务:

 Task.Factory.StartNew(()=> { Thread.Sleep(5000); form.Invoke(new Action(()=>DoSomething())); }); 

[编辑]

要传递间隔,只需将其存储在变量中:

 int interval = 5000; Task.Factory.StartNew(()=> { Thread.Sleep(interval); form.Invoke(new Action(()=>DoSomething())); }); 

[/编辑]

你看错了。 单击按钮,它会以x秒的间隔启动计时器。 当它们启动时,它的事件处理程序执行任务。

那么你不想发生什么。

虽然x秒已​​经过去了。?

当任务正在执行?

例如,如果您不希望在延迟和任务完成之前单击该按钮。 在按钮单击处理程序中禁用它,并在任务完成时启用它。

如果你想要的只是在任务之前延迟5秒,那么你应该将启动延迟传递给任务并让它处理它。

您的应用程序挂起,因为您正在主UI线程上调用5秒睡眠/等待。 把sleep / wait / what动作放在一个单独的线程中(实际上System.Windows.Forms.Timer应该为你做),当它完成时调用将某些控件变为绿色的动作。 记得检查InvokeRequired。 这是一个简短的示例(可以从另一个线程调用SetText,如果是调用将在文本框所在的主UI线程上调用):

 private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } } 

我从这里拿了样品(非常值得一读!)。

@eFloh在post中标注为答案说:

Tick事件可能在另一个无法修改你的gui的线程上执行,你可以抓住这个……

这不是文档所说的。
您正在示例代码中使用System.Windows.Forms.Timer。
这是一个Forms.Timer
根据C#docs,在UI线程上引发了Timer事件。

此Windows计时器专为使用UI线程执行处理的单线程环境而设计。 它要求用户代码具有可用的UI消息泵,并始终在同一个线程中运行…

另请参阅stackoverflowpost

我认为你正在寻找的是System.Timers ……我认为你不需要为你想要做的事情设置一个CWND计时器:看看http://msdn.microsoft.com/en- us / library / 0tcs6ww8(v = VS.90).aspx为例。 它应该做的伎俩。

你有没有尝试过

 public static Task Delay( int millisecondsDelay ) 

你可以像这样使用:

 await Task.Deplay(5000); 

参考: https : //msdn.microsoft.com/en-us/library/hh194873(v = vs.110).aspx