Johnny
Johnny

Reputation: 491

Asynchronous Displaying in Windows Form Application

I don't think the following question is rarely seen. But since I don't know how to search for the right answer, so I'm still stuck on it.

I have a label in the form and I want to show something before another job is invoked:

private void btnLoadEvent_Click(object sender, EventArgs e)
{
    lbStatus.Text = "Loading... ";
    load();
}
private void load() 
{ 
    Thread.Sleep(5000);
    lbStatus.Text = "Done";
}

The label won't show anything before load() is complete.

Then I changed my program usnig async/await:

private async void btnLoadEvent_Click(object sender, EventArgs e)
{
    lbStatus.Text = "Loading... ";
    await load();
}

private async Task load()
{
    Thread.Sleep(5000);
    lbStatus.Text = "Done";
}

It doesn't change anything. Does anyone have any idea?

2014/4/3:

As a note, I think I've figured out how async/await works. And to avoid misleading any possible reader, I list my final solution as follows:

private async void btnLoadEvent_Click(object sender, EventArgs e)
{
    lbStatus.Text = "Loading... ";
    string content = await loadAsync();
}
private async Task<string> loadAsync() 
{ 
    using (WebClient webClient = new WebClient())
    {
        string json = await webClient.DownloadStringTaskAsync(
                "http://api.openweathermap.org/data/2.5/weather?q=Taipei,tw");
        lbStatus.Text = "Done";
        return json;
    }
}

In practice, to meet the Decoupling Principle, "lbStatus.Text = ... " could be better moved from loadAsync() to btnLoadEvent_Click() although it works fine.

And thanks everyone who helped.

Upvotes: 2

Views: 6180

Answers (3)

Gleb
Gleb

Reputation: 1432

You need to use BackgroundWorker. Something like that.

private void button1_Click(object sender, EventArgs e)
{

    label1.Text = "Loading";
    backgroundWorker1.RunWorkerAsync();
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    load();
}

private void load()
{
   System.Threading.Thread.Sleep(1000);
   if(InvokeRequired)
      this.Invoke(new Action(()=>label1.Text = "Done"));
}

Upvotes: 0

spender
spender

Reputation: 120380

You didn't really go async. Thread.Sleep is blocking and because your async function never yields it will still block the call site. Use await Task.Delay(... instead.

private void btnLoadEvent_Click(object sender, EventArgs e)
{
    lbStatus.Text = "Loading... ";
    load();
}

private async Task load()
{
    await Task.Delay(5000);
    lbStatus.Text = "Done";
}

Upvotes: 3

K.L
K.L

Reputation: 7

Try using a BackgroundWorker . Set your label.Text to Loading before executing the BackgroundWorker's RunWorkerAsync method. Do your stuff (like your Thread.Sleep(5000)) in the Do_Work event and change the status of your label in the RunWorkerCompleted event. Visit this link to see an example.

Upvotes: 0

Related Questions