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

时间:2012-02-02 12:27:11

标签: c# winforms forms sleep wait

我知道C#和Windows窗体中有Thread.SleepSystem.Windows.Forms.Timer以及Monitor.Wait。我似乎无法弄清楚如何等待X秒然后再做其他事情 - 没有锁定线程。

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

8 个答案:

答案 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消息泵可用,并始终使用相同的操作   线程......

另见stackoverflow post here

答案 7 :(得分:0)

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