Thread.Sleep无法按我期望的那样在C#中工作

时间:2018-11-11 22:17:32

标签: c# thread-sleep

此代码模仿了我在应用程序中遇到的问题。

    private void button1_Click(object sender, EventArgs e)
    {
        button1.BackColor = Color.Red;
        Thread.Sleep(3000);
        button1.BackColor = Color.Green;
    }

我希望这段代码能够实现;

  • 将按钮设为红色
  • 等待3秒
  • 将按钮设为绿色

,而是等待3秒钟,然后将按钮变为绿色。我不能只是从一开始就将按钮设为绿色,因为这在我的大型应用程序中将无法使用。

有人知道什么是错的,还有我该如何解决?预先感谢。

3 个答案:

答案 0 :(得分:3)

不。它更改为红色,但您阻止了UI线程,因此看不到颜色更改。如果您将处理程序更改为async这样的

,该怎么办?
private async Task button1_Click(object sender, EventArgs e)
{
    button1.BackColor = Color.Red;
    await Task.Delay(3000);
    button1.BackColor = Color.Green;
}

答案 1 :(得分:2)

问题是使用Sleep会阻塞主(渲染)线程。因此,您将按钮设置为红色,但由于阻塞了线程,因此应用程序无法呈现该线程。实际上,我希望整个应用程序都冻结。
我不确定您在使用什么,但是请尝试看看一些计时器。

编辑或仅使用任务Delayed function calls。请不要使用线程。

答案 2 :(得分:0)

这样做的技术原因是,UI在消息泵上工作(对于WinForms或类似的WPF)。基本上,消息泵是要执行的工作项目的队列,以及如下所示的while循环

while(GetMessage(&msg, NULL, 0, 0) > 0) 
{ 
  TranslateMessage(&msg); 
  DispatchMessage(&msg); 
}

正在发生的事情是,在您处理点击时

  1. 点击进入消息队列
  2. 被消息泵处理
  3. 进入点击方法
  4. 将线程阻塞x秒钟,该线程仍在您的方法中,并且泵无法处理。

为什么?

Thread.Sleep()

  

挂起当前线程指定的时间。

简而言之,没有其他消息得到处理。在您的示例中,您在泵还没有时间来处理您的颜色更改之前就休眠了该线程(它仍然会处理您的单击)。

当邮件最终得到处理时,它会处理待办事项(您的颜色更改是其中的一部分),然后在不暂停的情况下迅速将其从一个更改为另一个。

修复非常简单,您需要让泵在等待时处理消息,而正如其他答案所难免的那样,在.net上的现代版本中,我们可以使用async await模式,并利用Task.Delay()方法。

程序处理带有await前缀的任何内容时,

  1. 如果您在UI线程上,它将捕获上下文
  2. 从另一个线程开始并继续执行
  3. 让消息泵继续处理。
  4. 任务完成(延迟结束)后,它将控制权返回到原始上下文(您从中调用该线程的线程)。

嘿。一切都应该如此