【问题标题】:Code not executing before thread sleep?代码在线程睡眠之前没有执行?
【发布时间】:2016-11-10 06:28:15
【问题描述】:

我这样做:

clear();
coinRefundComplete.Visible = true;
state = 0;

System.Threading.Thread.Sleep(4000);
clear();

greeting.Visible = true;
rate.Visible = true;
refundTicket.Visible = true;
currentTime.Visible = true;

我希望 coinRefundComplete 文本(它是一个标签)出现 4 秒钟,然后通过我用 clear() 定义的方法清除,然后发生其他一些事情。相反,在我使用第一个 clear() 清除表单后,我的表单空白 4 秒,然后正确完成。

【问题讨论】:

  • 你阻塞了 UI 线程。更改将不可见,您永远不应该阻止它。如果您想暂时展示一些东西,请使用计时器。
  • 如果所有这些代码都在一个方法中 - 那么在方法完全执行之前不会更新表单。
  • System.Threading.Thread.Sleep(4000); 之前插入 Application.DoEvents(); - 让 UI 有机会重绘标签
  • @Fabio,你是说我不能在 1 种方法中多次清除表格?
  • @DmitryBychenko - Application.DoEvents() 不好。与在 UI 线程上调用 Thread.Sleep(...) 一样糟糕 - 或者可能更糟糕。

标签: c# .net multithreading winforms


【解决方案1】:

使用async/await 方法。
将您的方法设为async - 下面是按钮单击事件处理程序的示例

private async void ButtonClick(object sender, EventArgs e)
{
    clear();
    coinRefundComplete.Visible = true;
    state = 0;

    await Task.Delay(4000);
    clear();

    greeting.Visible = true;
    rate.Visible = true;
    refundTicket.Visible = true;
    currentTime.Visible = true;
}

在线await Task.Delay(4000); UI线程将被释放,它将更新之前所做的所有更改。 4 秒后方法将继续在 UI 线程上执行。

【讨论】:

  • 谢谢,这就是我要找的。我使用这种技术找到了多个问题和答案,但没有一个指出我需要在按钮单击的方法定义中添加“异步”。
  • 虽然我认为这个实现更好,因为它不会冻结 UI,但我将另一个答案标记为正确,因为它提供了一个使用与我原来的问题相同的想法的解决方案(尽管不是很好的整体解决方案)。
  • @73est - 另一种解决方案是个坏主意。它不能保证工作。你永远不应该只是休眠 UI 线程。这个答案要好得多。
  • 我明白这一点,我在我的实现中使用了这个解决方案。但就目前而言,另一个解决方案回答了我在这种情况下理论上如何使用 Thread.Sleep() 的问题
【解决方案2】:

虽然让 GUI 线程进入睡眠状态是不可取的,但允许 GUI 线程在进入睡眠状态之前刷新控件状态会显示您想要的更改。在使其可见之后和进入睡眠之前调用Control.UpdateControl.Refresh,以便 GUI 线程能够在进入睡眠之前显示更改。

clear();
coinRefundComplete.Visible = true;
label1.Update();
state = 0;    
System.Threading.Thread.Sleep(4000);
clear();

您在使用Thread.Sleep 时应该小心,在您的情况下,它是 GUI 线程,并且 GUI 会在您睡觉时无响应。知道你想要阻塞线程的原因可能会带来其他更好的建议。

编辑

您可以使用其他线程来增加延迟,而不会阻塞 GUI 线程。如果您可以使用框架 4.5,那么您可以使用 async / await 构造或阅读这篇文章 Using async/await without .NET Framework 4.5

private async void testAsyncAwaitDely_Click(object sender, EventArgs e)
{
     clear();
     coinRefundComplete.Visible = true;
     state = 0;
     await Task.Delay(4000);
     clear();
     //Your code
}

【讨论】:

    【解决方案3】:

    更新 [2018 年 4 月 22 日]:我没有删除此答案,因此即使我的答案确实是 a,您也不会走错路OP问题的可能解决方案(特别是当它也让我失去一些负面声誉时)。你应该阅读下面的帖子来真正说服自己为什么Application.DoEvents 不是解决这个问题的好方法:


    您的 UI 没有刷新,因为您正在 UI 线程上进行整个处理,因此 UI 线程没有任何机会刷新 UI 元素。您需要在任何地方调用 Application.DoEvents() 函数来刷新 UI 并加载最新更改。这是您修改后的代码。我在当前 UI 线程上调用 sleep 之前添加了一行代码:

            clear();
            coinRefundComplete.Visible = true;
            state = 0;
    
            //new line of code
            System.Windows.Forms.Application.DoEvents();
    
            System.Threading.Thread.Sleep(4000);
            clear();
    
            greeting.Visible = true;
            rate.Visible = true;
            refundTicket.Visible = true;
            currentTime.Visible = true;
    

    【讨论】:

    • 打电话给Application.DoEvents() 很糟糕。很坏。它可能导致各种重入错误。它之所以可用,是因为它向后兼容 VB6。不惜一切代价避免它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 2011-03-28
    相关资源
    最近更新 更多