Ash Ash - 1 month ago 15
C# Question

Simulate loading with Thread.Sleep()

(Edit - This is for learning purposes only the program is completely pointless)

I'm trying to make it look like my program is loading using

Thread.Sleep()
with a randomly generated number. It works and it waits the time but for some reason it will not display the history variable on screen until after all of the sleeps have happened.

It should do this


  • Print logging in...

  • Sleep for 5-10 seconds

  • print verifying details...

  • sleep for 5-10 seconds

  • print Logged in.



The reason I am appending the history string is because I want to keep all previous prints on the screen and I'm new to programming so I thought this is the easiest way.

private void Loading()
{
Random rnd = new Random();
int wait1 = rnd.Next(5000, 10000 );
history = "Logging in...\n";
historyLbl.Text = history;
System.Threading.Thread.Sleep(wait1);
int wait2 = rnd.Next(5000, 10000);
history = history + "Verifying Details...\n";
historyLbl.Text = history;
System.Threading.Thread.Sleep(wait2);
history = history + "Logged in.\n";
historyLbl.Text = history;


}

Answer

When you use Thread.Sleep(), it blocks the thread. Like a red light, nothing can move until the block is lifted. In simple Windows Forms applications, the UI thread also runs all of your code. So when you block the thread in a method, you're also blocking the UI.

A nice trick to do something like this is to use the async and await operators, along with Task.Delay()

// Note the change in signature
private async Task Loading()
{
    Random rnd = new Random();
    int wait1 = rnd.Next(5000, 10000 );
    history = "Logging in...\n";
    historyLbl.Text = history;

    await Task.Delay(wait1);

    int wait2 = rnd.Next(5000, 10000);
    history = history + "Verifying Details...\n";
    historyLbl.Text = history;

    await Task.Delay(wait2);

    history = history + "Logged in.\n";
    historyLbl.Text = history;
}

This uses a special language feature that essentially does the waiting on a whole separate thread and comes back to your code when it finishes. That's why the UI won't freeze.

Ok, I'm wrong here. Async and await have allways been a bit mysterious and I guess I just assumed.

Note that anywhere you call this method, you will also need to await it. If you do it on a button click for example, you need to change the button click event handler

// async void is a special pattern for event handlers, to allow them to use async. 
// in general you should always use async Task
private async void Button_Click(object sender, EventArgs e)
{
    await Loading();
}

But the bigger question is why would you ever do this? The user never wants to wait longer than they have to. Every once in a while I use Task.Delay() to allow my UI thread to catch up, but thats only for 20ms at most.