【问题标题】:Thread.Sleep(300) not working correctlyThread.Sleep(300) 无法正常工作
【发布时间】:2019-02-05 16:15:23
【问题描述】:

我希望它执行第一部分代码,然后让pictureBox可见,暂停3秒,隐藏pictureBox并执行其余代码:

// first part of the code here
pb_elvisSherlock.Visible = true;
Thread.Sleep(300);
pb_elvisSherlock.Visible = false;
// rest of the code here

但它会执行整个代码块,然后才会暂停。有什么想法吗?

谢谢!

【问题讨论】:

  • 不应该是Thread.Sleep(3000);吗?我相信Thread.Sleep 的输入以毫秒为单位。
  • 已更改,它确实暂停了更长的时间,但我的图片框仍然没有出现。
  • 您可能需要给您的照片一个绘画的机会。在调用 Thread.Sleep() 之前,应该有一个 Update() 方法或类似的方法可以调用。由于这些类型的原因,最好使用计时器,这样其他一切都可以继续工作。
  • 您确定要为此阻止 UI 线程吗?
  • 不,我不想阻止用户界面。那么还有其他方法可以使用定时器吗?

标签: c# winforms multithreading sleep


【解决方案1】:

如果您试图让PictureBox 出现 3 秒,您可能希望您的应用程序在此期间保持响应。因此,使用Thread.Sleep 不是一个好主意,因为您的 GUI 线程在睡眠时不会处理消息。

更好的选择是将System.Windows.Forms.Timer 设置为 3000 毫秒,在 3 秒后隐藏PictureBox 而不会阻塞您的 GUI。

例如,像这样:

pb.Visible = true;
var timer = new Timer();
timer.Tick += () => { pb.Visible = false; timer.Stop(); };
timer.Interval = 3000;
timer.Start();

【讨论】:

    【解决方案2】:
    pb_elvisSherlock.Visible = true;
    Application.DoEvents(); //let the app show the picturebox
    Thread.Sleep(3000);
    pb_elvisSherlock.Visible = false;
    

    问题是在暂停 GUI 线程之前,您没有让消息循环有机会显示图片框。 Application.DoEvents() 解决这个问题。

    请注意,在 GUI 线程上使用 Thread.Sleep 会使绘画冻结(当 Sleep 处于活动状态时,请尝试在您的应用上移动一个窗口)。

    你应该这样做:

    pb_elvisSherlock.Visible = true;
    int counter = 0;
    while (counter < 30)
    {
      Application.DoEvents(); 
      Thread.Sleep(100);
      ++counter;
    }
    pb_elvisSherlock.Visible = false;
    

    这仍然是一种 hack,但窗口将被重新绘制并做出应有的响应。

    更新 2

    嗯。 DoEvents 似乎有点像黑客。 (感谢 cmets)。

    如果图片框是一种唠叨屏幕,请执行以下操作:

    备选方案 1

    1. 创建一个仅包含图片框的新表单(不要在该表单上使用边框)。
    2. 向该表单添加一个计时器,在三秒后调用Close
    3. 调用“myNagForm.DoModal()”

    当 nagform 可见时,该解决方案会阻止您的用户在“正常”表单中执行任何操作。

    备选方案 2

    1. 创建一个后台工作者,例如:http://dotnetperls.com/backgroundworker
    2. 将您的图片框及其后执行的代码移至后台工作方法。

    【讨论】:

    • 就像你说的,Application.DoEvents() 有点小技巧。它会导致消息循环处理待处理的消息,这可能会导致其他事件被触发并使您陷入混乱。这也意味着您仍然会阻塞您的 UI 线程 3 秒钟,这将使您的应用程序无响应。使用 while 循环旋转与强制重复调用消息泵一样糟糕。我建议您改为使用background thread 来等待。
    • 在这 3 秒内关闭窗口以查看 DoEvents 的问题。
    • 请参阅:Keeping your UI Responsive and the Dangers of Application.DoEvents,了解为什么应该避免 DoEvents 以支持正确的线程处理。
    • @jgauffin:很适合听取反馈和更新。备选方案 2 绝对是最佳选择。
    【解决方案3】:

    问题是您阻塞了 UI 线程,这是负责重绘表单的线程,因此在您等待的 3 秒内没有重绘任何内容(尝试在这 3 秒内拖动您的表单,然后'会看到它完全没有反应)。

    有很多方法可以解决这个问题,但基本前提是首先您需要在后台线程上等待,以便您的 UI 线程保持响应(选项包括使用BackgroundWorkerTimerThreadPoolThreadTPL TaskFactory)。其次,您必须记住,对 UI 的任何更新都必须在 UI 线程上完成,因此您必须切换回您的 UI 线程(使用.Invoke()TaskScheduler),然后才能隐藏最后的图片框。

    此示例使用 TPL(任务并行库):

    // Start by making it visible, this can be done on the UI thread.
    pb_elvisSherlock.Visible = true;
    
    // Now grab the task scheduler from the UI thread.
    var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    
    // Now create a task that runs on a background thread to wait for 3 seconds.
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(3000);
    
    // Then, when this task is completed, we continue...
    }).ContinueWith((t) =>
    {
        //... and hide your picture box.
        pb_elvisSherlock.Visible = false;
    
    // By passing in the UI scheduler we got at the beginning, this hiding is done back on the UI thread.
    }, uiScheduler);
    

    【讨论】:

      【解决方案4】:

      首先你只睡了 300 毫秒而不是 3 秒

      Thread.Sleep(3000);
      

      第二个你的用户界面将在你的代码执行完成后首先更新,所以你需要做类似this的操作

      【讨论】:

        【解决方案5】:

        我会尽量延长这个时间:

        Thread.Sleep(300);
        

        改成

        Thread.Sleep(3000);
        

        在您的示例中,您只暂停了 0.3 秒(3000 = 3 秒)。如果我不得不猜测,您没有等待足够长的时间来显示窗口。代码实际上工作正常。

        像评论一样尝试在设置可见性属性后添加Application.DoEvents();

        【讨论】:

        • ... 或 3 秒 / 3000 毫秒,如 OP 想要。 +1
        • 仍然看不到我的图片框出现。 :)
        • 在运行 Sleep(3000) 之前强制重绘。
        • 它不仅仅是几秒钟 :) 即使我只是使用“ pb_elvisMerilyn.Visible = true; Thread.Sleep(3000); ”它会先暂停然后显示图片。有点糟糕。
        • 问题是因为他阻塞了UI线程,而不是时间长短。
        【解决方案6】:

        扩展在这种情况下非常有用 ;-)

        public static class IntExtensions
        {
            public static TimeSpan Seconds(this int value)
            {
                return new TimeSpan(0, 0, value);
            }
        }
        
        Thread.Sleep(3.Seconds());
        

        【讨论】:

        • 它不仅仅是几秒钟 :) 即使我只是使用“ pb_elvisMerilyn.Visible = true; Thread.Sleep(3000); ”它会先暂停然后显示图片。有点糟糕。
        • 只是关于使用毫秒的评论以及这有多烦人。 kim thomsens 的答案应该是正确的 :-)
        • 为什么不只是TimeSpan t = TimeSpan.FromSeconds(3)?为此使用扩展方法是非常愚蠢的。
        • 他吉姆,您能详细说明一下令人难以置信的愚蠢部分吗?获得自然英语(因此可读性更好)源代码有什么问题? 3.Seconds() 绝对比 TimeSpan.FromSeconds(3) 更具可读性
        • 如果你要这样做,那么你最好添加MillisecondsMinutesHoursDays的扩展方法,以及相应的扩展方法所有标准类型。我希望写3.50.Seconds(),并且还能够转换doublelongbyte。您最终编写了大量很少(如果曾经)使用的代码,并在您的代码中创建了对扩展方法类的依赖关系。所有这些都是为了节省少量按键,并且可以说是可读性较差的代码。这是“仅仅因为你可以,并不意味着你应该”的一个例子。
        【解决方案7】:

        你可以试试这个Task.Delay(TimeSpan.FromSeconds(3)).Wait();,只要 Thread.Sleep 方法有时不会阻塞线程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-12-01
          • 2012-11-04
          • 1970-01-01
          • 2016-09-01
          • 2012-07-11
          • 2018-04-08
          相关资源
          最近更新 更多