等待几秒钟而不阻止UI执行

时间:2014-03-03 21:53:57

标签: c# timer wait

我想在两条指令之间等待几秒钟,但没有阻止执行。

例如,Thread.Sleep(2000)它不好,因为它会阻止执行。

我的想法是我调用一个方法,然后等待X秒(例如20)监听一个事件。在20秒结束时,我应该根据20秒内发生的事情进行一些操作。

10 个答案:

答案 0 :(得分:78)

我认为你所追求的是Task.Delay。这不像Sleep那样阻塞线程,这意味着你可以使用异步编程模型使用单个线程来完成这个。

async Task PutTaskDelay()
{
    await Task.Delay(5000);
} 

private async void btnTaskDelay_Click(object sender, EventArgs e)
{
    await PutTaskDelay();
    MessageBox.Show("I am back");
}

答案 1 :(得分:23)

我用:

private void WaitNSeconds(int segundos)
{
    if (segundos < 1) return;
    DateTime _desired = DateTime.Now.AddSeconds(segundos);
    while (DateTime.Now < _desired) {
         System.Windows.Forms.Application.DoEvents();
    }
}

答案 2 :(得分:11)

这是使用另一个线程的好例子:

// Call some method
this.Method();

Task.Factory.StartNew(() =>
{
    Thread.Sleep(20000);

    // Do things here.
    // NOTE: You may need to invoke this to your main thread depending on what you're doing
});

上面的代码需要.NET 4.0或更高版本,否则请尝试:

ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
    Thread.Sleep(20000);

    // Do things here
}));

答案 3 :(得分:10)

如果您无法将环境升级到.NET 4.5以获得对异步和等待API的访问权限,那么Omar的解决方案就不错了。也就是说,为了避免表现不佳,应该进行一项重要的改变。在调用Application.DoEvents()之间应该稍加延迟,以防止过多的CPU使用。添加

Thread.Sleep(1);

在调用Application.DoEvents()之前,您可以添加这样的延迟(1毫秒)并阻止应用程序使用它可用的所有cpu周期。

private void WaitNSeconds(int seconds)
{
    if (seconds < 1) return;
    DateTime _desired = DateTime.Now.AddSeconds(seconds);
    while (DateTime.Now < _desired) {
         Thread.Sleep(1);
         System.Windows.Forms.Application.DoEvents();
    }
}

*有关使用Application.DoEvents()的潜在缺陷的更详细讨论,请参阅https://blog.codinghorror.com/is-doevents-evil/

答案 4 :(得分:3)

如果您不想阻止事物并且也不想使用多线程,这里有适合您的解决方案: https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx

UI线程未被阻止,计时器等待2秒后再做一些事情。

以下是来自上述链接的代码:

        // Create a timer with a two second interval.
    aTimer = new System.Timers.Timer(2000);
    // Hook up the Elapsed event for the timer. 
    aTimer.Elapsed += OnTimedEvent;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program... ");
    Console.ReadLine();
    Console.WriteLine("Terminating the application...");

答案 5 :(得分:2)

我真的不赞成你使用Thread.Sleep(2000),因为有几个原因(有些原因被描述为here),但最重要的是因为它在调试/测试方面没用。

我建议使用C# Timer代替Thread.Sleep()。定时器允许您经常执行方法(如果需要)并且更容易在测试中使用!有一个非常好的例子,说明如何在超链接后面使用计时器 - 只需将你的逻辑“2秒后发生的事情”直接放入Timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);方法。

答案 6 :(得分:0)

查看System.Threading.Timer课程。我认为这就是你要找的东西。

code example on MSDN似乎表明此课程与您尝试的内容非常相似(在一定时间后检查状态)。

答案 7 :(得分:0)

嗨,这是我的建议

 .......
var t = Task.Run(async () => await Task.Delay(TimeSpan.FromSeconds(Consts.FiveHundred)).ConfigureAwait(false));
                //just to wait task is done
                t.Wait();

请牢记“等待”,否则“延迟”运行不会影响应用程序

答案 8 :(得分:-1)

如果可能的话,首选方法应该是使用异步方式或第二个线程。

如果不可能或不希望这样做,则使用DoEvents()的任何实现都是一个坏主意,因为它可能会导致问题Possible problems with DoEvents。这主要是关于带有Winforms的DoEvent,但是WPF中可能存在的陷阱是相同的。

然后可以使用带有所需睡眠时间的框架放在分派器上:

using System;
using System.Threading;
using System.Windows.Threading;

public static void NonBlockingSleep(int timeInMilliseconds)
{
    DispatcherFrame df = new DispatcherFrame();

    new Thread((ThreadStart)(() =>
    {
        Thread.Sleep(TimeSpan.FromMilliseconds(timeInMilliseconds));
        df.Continue = false;

    })).Start();

    Dispatcher.PushFrame(df);
}

答案 9 :(得分:-1)

在我的情况下,我需要执行此操作,因为我已将一个方法传递给正在等待的线程,并且由于该方法在GUI线程上运行,并且线程代码有时称为该方法,因此导致了锁定。

Task<string> myTask = Task.Run(() => {
    // Your code or method call
    return "Maybe you want to return other datatype, then just change it.";
});
// Some other code maybe...
while (true)
{
    myTask.Wait(10);
    Application.DoEvents();
    if (myTask.IsCompleted) break;
}