ChiliYago ChiliYago - 1 month ago 8
C# Question

Updating UI from events using asyc await

I am trying to understand how to update a UI from an event while using async/await pattern.
Below is the test code I am using on a WinForm app. I am not even sure this is the right way to go about it. What is necessary to allow the pwe_StatusUpdate method to update the UI? The cross-thread operation error is thrown there.

Thanks for reading.

// calling code
ProcessWithEvents pwe = new ProcessWithEvents();
pwe.StatusUpdate += pwe_StatusUpdate;
await pwe.Run();



void pwe_StatusUpdate(string updateMsg)
{
// Error Here: Cross-thread operation not valid: Control '_listBox_Output' accessed from a thread other than the thread it was created on.
_listBox_Output.Items.Add(updateMsg);
}


-

// Class with long running process and event
public delegate void StatusUpdateHandler(string updateMsg);

public class ProcessWithEvents
{
public event StatusUpdateHandler StatusUpdate;

public async Task Run()
{
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{

RaiseUpdateEvent(String.Format("Update {0}", i));

Thread.Sleep(500);
}
});

}

private void RaiseUpdateEvent(string msg)
{
if (StatusUpdate != null)
StatusUpdate(msg);
}
}


-

Answer Source

The async pattern has support for progress updates.

In short, your async method can take an IProgress<T>, and your calling code passes in an implementation of that interface (usually Progress<T>).

public class ProcessWithUpdates
{
  public async Task Run(IProgress<string> progress)
  {
    await Task.Run(() =>
    {
      for (int i = 0; i < 10; i++)
      {
        if (progress != null)
          progress.Report(String.Format("Update {0}", i));
        Thread.Sleep(500);
      }
    });
  }
}

// calling code
ProcessWithUpdates pwp = new ProcessWithUpdates();
await pwp.Run(new Progress<string>(pwp_StatusUpdate));