2

I want it to execute the first part of the code, then make the pictureBox visible, pause for 3 seconds, hide the pictureBox and execute the rest of the code:

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

But it executes the whole block of code and only then pauses. Any ideas what to do?

Thanks!

Ran
  • 5,989
  • 1
  • 24
  • 26
Rob
  • 719
  • 5
  • 11
  • 16
  • 1
    shouldn't that be `Thread.Sleep(3000);`? I believe the input to `Thread.Sleep` is in milliseconds. – Josh Dec 22 '10 at 14:56
  • changed, it does pause longer, but my pictureboxes still don't appear. – Rob Dec 22 '10 at 14:58
  • 2
    You might need to give your picture a chance to paint. There should be an Update() method or something similar you can call before calling Thread.Sleep(). For these types of reasons, it may be better to use a timer so everything else can keep working. – Jonathan Wood Dec 22 '10 at 15:05
  • 2
    Are you sure you want to block the UI thread for this? – R. Martinho Fernandes Dec 22 '10 at 15:07
  • No, I don't want to block the UI. Is there any other way then to use a Timer? – Rob Dec 22 '10 at 15:08

7 Answers7

11

If you are trying to make a PictureBox appear for 3 seconds, you probably want your application to remain responsive during this time. So using Thread.Sleep is not a good idea because your GUI thread does not process messages while sleeping.

A better alternative would be to set a System.Windows.Forms.Timer for 3000 ms, to hide the PictureBox after 3 seconds without blocking your GUI.

For example, like this:

pb.Visible = true;
var timer = new Timer();
timer.Tick += () => { pb.Visible = false; timer.Stop(); };
timer.Interval = 3000;
timer.Start();
YoG
  • 111
  • 3
6
pb_elvisSherlock.Visible = true;
Application.DoEvents(); //let the app show the picturebox
Thread.Sleep(3000);
pb_elvisSherlock.Visible = false;

The problem is that you don't give the message loop a chance to display the picture box before you pause the GUI thread. Application.DoEvents() solve that.

Note that using Thread.Sleep on the GUI thread will make the painting freeze (try move a window over your app when the Sleep is active).

You should do something like this:

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

It's still kind of a hack but the window will be redrawn and respond as it should.

Update 2

Well. DoEvents seems to be a bit to much of a hack. (thanks for the comments).

If the picturebox is a kind of a nag screen do something like this:

Alternative 1

  1. Create a new form containing only the picturebox (don't use a border on that form).
  2. Add a timer to that form that calls Close after three seconds
  3. Call 'myNagForm.DoModal()'

That solution prevents your users from doing anything in your "normal" form while the nagform is visible.

Alternative 2

  1. Create a background worker, see here for example: http://dotnetperls.com/backgroundworker
  2. Move your picturebox AND the code executed after it to the background worker method.
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • Like you say, Application.DoEvents() is a bit of a hack. It causes the Message loop to process pending messages, which can cause other events to get triggered and leave you in a bit of a mess. It also means you are still blocking your UI thread for 3 seconds which will leave your application unresponsive. Using a while loop to spin is equally bad as your forcing the message pump to be called repeatedly. I would recommend instead you use a [background thread](http://stackoverflow.com/questions/4510397/thread-sleep300-not-working-correctly/4510615#4510615) to do your waiting. – Simon P Stevens Dec 22 '10 at 15:22
  • 1
    Close the window within those 3 seconds to see the problem with DoEvents. – Hans Passant Dec 22 '10 at 15:29
  • 1
    See: [Keeping your UI Responsive and the Dangers of Application.DoEvents](http://blogs.msdn.com/b/jfoscoding/archive/2005/08/06/448560.aspx) for reasons why DoEvents should be avoided in favour of proper thread handling. – Simon P Stevens Dec 22 '10 at 15:30
  • @jgauffin: Nice one for listening to feedback and updating. Alternative 2 is definitely the best option. – Simon P Stevens Dec 22 '10 at 15:58
3

I would try making this longer:

Thread.Sleep(300);

change to

Thread.Sleep(3000);

You are only pausing for .3 seconds in your example (3000 = 3 seconds). If I had to guess, you aren't waiting long enough for the window to display. The code is actually working correctly.

Like the comment try adding in Application.DoEvents(); after setting the visibility property.

kemiller2002
  • 113,795
  • 27
  • 197
  • 251
3

The problem is that you are blocking the UI thread, which is the thread responsible for doing the redrawing of your form, so nothing gets redrawen during the 3 seconds you are waiting (Try draging your form around during these 3 seconds and you'll see it's totally unresponsive).

There are loads of ways of dealing with this, but the basic premise is that firstly you need to do your waiting on a background thread so your UI thread remains responsive (Options include using a BackgroundWorker, a Timer, the ThreadPool, a Thread or the TPL TaskFactory). Secondly, you must remember that any update to the UI must be done on the UI thread, so you must switch back to your UI thread (Using .Invoke() or a TaskScheduler) before you hide the picture box at the end.

This example uses the TPL (Task Parallel Library):

// 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);
Simon P Stevens
  • 27,303
  • 5
  • 81
  • 107
2

First of all you are only sleeping for 300 milliseconds not 3 seconds

Thread.Sleep(3000);

Second your User interface will first be updated when your code is done executing, so you need to do something like this

Community
  • 1
  • 1
Kimtho6
  • 6,154
  • 9
  • 40
  • 56
1

You can try this Task.Delay(TimeSpan.FromSeconds(3)).Wait(); wherever Thread.Sleep method sometimes doesn't block the thread.

Hayrullah Cansu
  • 262
  • 5
  • 14
0

Extensions are quite helpful in such situations ;-)

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

Thread.Sleep(3.Seconds());
Stephan Schinkel
  • 5,270
  • 1
  • 25
  • 42
  • its not just about the seconds :) even if i just use " pb_elvisMerilyn.Visible = true; Thread.Sleep(3000); " it will first pause and then show the picture. kinda wice wersa. – Rob Dec 22 '10 at 15:04
  • was just a comment about using milliseconds and how irritating this is. kim thomsens answer should be right :-) – Stephan Schinkel Dec 22 '10 at 15:07
  • And why not just `TimeSpan t = TimeSpan.FromSeconds(3)`? It's incredibly silly to use extension methods for this. – Jim Mischel Dec 22 '10 at 15:33
  • him jim, can you please elaborate more on the incredibly silly part? what's wrong in getting natural english language (and therefore better readable) source code? 3.Seconds() is definitely more readable than TimeSpan.FromSeconds(3) – Stephan Schinkel Dec 22 '10 at 15:38
  • 1
    If you're going to do that, then you'd better add extension methods for `Milliseconds`, `Minutes`, `Hours`, and `Days`, as well as corresponding extension methods for all of the standard types. I'd expect to write `3.50.Seconds()`, and also be able to convert a `double` or `long` or `byte`. You end up writing a huge amount of code that's rarely (if ever) used, and create a dependency in your code on the extension methods classes. All for the marginal savings of a few keystrokes, and arguably less readable code. This is an example of "Just because you can, doesn't mean you should." – Jim Mischel Dec 27 '10 at 20:14