我知道C#和Windows窗体中有Thread.Sleep
和System.Windows.Forms.Timer
以及Monitor.Wait
。我似乎无法弄清楚如何等待X秒然后再做其他事情 - 没有锁定线程。
我有一个带按钮的表格。单击按钮,计时器将启动并等待5秒钟。在这5秒钟后,表格上的其他一些控件显示为绿色。使用Thread.Sleep
时,整个应用程序将在5秒内无响应 - 所以我如何“在5秒后做某事”?
答案 0 :(得分:29)
(由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 and await”。
答案 1 :(得分:10)
您可以启动执行操作的异步任务:
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()));
});
<强> [/ EDIT] 强>
答案 2 :(得分:3)
您尝试过
public static Task Delay(
int millisecondsDelay
)
您可以这样使用:
await Task.Deplay(5000);
参考:https://msdn.microsoft.com/en-us/library/hh194873(v=vs.110).aspx
答案 3 :(得分:2)
您可以按照自己的方式等待UI线程。
Task.Factory.StartNew(async() =>
{
await Task.Delay(2000);
// it only works in WPF
Application.Current.Dispatcher.Invoke(() =>
{
// Do something on the UI thread.
});
});
答案 4 :(得分:1)
您的应用程序挂起,因为您正在主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;
}
}
我从here中取样(非常值得一读!)。
答案 5 :(得分:1)
你看错了。 单击按钮,它会以x秒的间隔启动计时器。当它们启动时,它的事件处理程序执行任务。
那么你想要发生什么。
虽然x秒已经过去了。?
当任务正在执行时?
例如,如果您不希望点击该按钮,直到延迟和任务完成。在按钮单击处理程序中禁用它,并在任务完成时启用它。
如果您想要的任务是在任务之前延迟五秒钟,那么您应该将启动延迟传递给任务并让它处理它。
答案 6 :(得分:1)
@eFloh在标记为答案的帖子中说:
可以在另一个无法修改的线程上执行Tick事件 你的gui,你可以抓住这个......
这不是文档所说的 您在示例代码中使用System.Windows.Forms.Timer 那是一个 Forms.Timer 根据C#docs,在UI线程上引发了Timer事件。
此Windows计时器专为单线程环境而设计 UI线程用于执行处理。它需要用户 代码有一个UI消息泵可用,并始终使用相同的操作 线程......
答案 7 :(得分:0)
我认为你要找的是System.Timers
......我认为你不需要为你想要做的事情设置一个CWND计时器:看一下http://msdn.microsoft.com/en-us/library/0tcs6ww8(v=VS.90).aspx例。应该这样做。