C# in Async Task change Label Text

2020-03-05 04:18发布

问题:

The following Code does not change the Text and stops executing the Task

private void button1_Click(object sender, EventArgs e)
    {
        label1.Text = "Test";
        Task.Run(() => MyAsyncMethod());
    }

    public async Task MyAsyncMethod()
    {
        label1.Text = "";
        //everything from here on will not be executed
    }

would be really handy if you could use async together with the UI

回答1:

for accessing a GUI control through a second thread you need to invoke. following example shows how to set a label's text properly

  private void setLabel1TextSafe(string txt)
  { 
       if(label1.InvokeRequired)
           label1.Invoke(new Action(() => label1.Text = txt));
       else
           label1.Text = txt;
  }

I hope this solves your problem



回答2:

would be really handy if you could use async together with the UI

The design of async was carefully done so you can use it naturally with the UI.

in my code i run a function that does a lot of IO and stuff that takes a long time

If you have asynchronous I/O methods (which you should), then you can just do this:

private async void button1_Click(object sender, EventArgs e)
{
  label1.Text = "Test";
  await MyMethodAsync();
}

public async Task MyMethodAsync()
{
  label1.Text = "";
  await ...; // "lot of IO and stuff"
  label1.Text = "Done";
}

That's the most natural approach.

However, if you need to run code on a background thread (e.g., it's actually CPU-bound, or if you just don't want to make your I/O operations asynchronous like they should be), then you can use IProgress<T>:

private void button1_Click(object sender, EventArgs e)
{
  label1.Text = "Test";
  var progress = new Progress<string>(update => { label1.Text = update; });
  await Task.Run(() => MyMethod(progress));
}

public void MyMethod(IProgress<string> progress)
{
  if (progress != null)
    progress.Report("");
  ...; // "lot of IO and stuff"
  if (progress != null)
    progress.Report("Done");
}

Under no circumstances should modern code use Control.Invoke or (even worse) Control.InvokeRequired.



回答3:

Task.Run is used to envelope an Action (that is not async) into a Task. Any Task that you want to execute should be awaited. Thus, that Task.Run of yours is rigorously doing nothing.

Mark that button1_Click event handler of yours as async. Then remove that Task.Run and instead do await MyAsyncMethod().



回答4:

Try this. You don't need to fire a new thread to invoke the async method. compiler will do it for you.

private void button1_Click(object sender, EventArgs e)
    {
        label1.Text = "Test";
        MyAsyncMethod();
    }
public async Task MyAsyncMethod()
{
    return await Task.Run(() =>{
    label1.Text = "";
    //everything from here on will not be executed
     }
}


回答5:

I think both the questions and some of the answers are not clear. Depending on where in the task thread you need to update the label you have to use invoke. Otherwise you can leverage await and leverage the standard semantics.

    private async void button1_Click(object sender, EventArgs e)
    {
        label1.Text = "Starting to run a long task... carry on...";
        await snooze(3);
        label1.Text = "Done with long task";
    }

    public Task<int> snooze(int seconds)
    {
        label1.Text = "zzzz...";
        return Task.Run(
        () => {
            label1.Invoke(new Action(() => label1.Text = "For some reason I need to alert you here.. bad dream perhaps...direct access to label1 will fail"));
            Thread.Sleep(seconds * 1000);
            return  seconds;
           });

    }