2

I have a MainWindow with a TextBlock and a Button controls on it, by clicking on which the RunAsync(int) method is called. It was doing some calculations, so the process took quite a long time and blocked the UI. I was able to move it to an asynchronous thread, but I am completely stuck on how best to implement updating the interface from this method every iteration of the For loop. Using the progress bar, for example.

At the moment i have the following code:

public partial class MainWindow : Window
{
    public MainWindow() => InitializeComponent();

    private async Task<List<int>> RunAsync(int par)
    {
        return await Task.Run(() =>
        {
            List<int> list = new List<int>();
            for (int i = 0; i < par;  i++)
            {
                // some code, that takes quite a long time
                Thread.Sleep(500); 
                list.Add(i);
            }
            return list;
        });
    }
    
    private async void StartBtn_Click(object sender, RoutedEventArgs e)
    {
        int count = (await RunAsync(5)).Count;
        label.Text = count.ToString();
    }
}
7
  • 2 things: 1 instead of Thread.Sleep... you should use Task.Delay. 2: use the Dispatcher to update the UI from a different thread Commented Apr 6, 2021 at 12:35
  • ... or simply use binding ... bind property from some class which implements INotyfiPropertyChanged and set it's instance as DataContext of MainWindow ... then from worker thread update this property ... that's it Commented Apr 6, 2021 at 12:38
  • 2
    You may not even need to call the Dispatcher. Just move the async call into the loop body, i.e. run and await an async method and update the UI in each loop iteration. Commented Apr 6, 2021 at 12:42
  • 1
    You may want to take a look at the Progress<T> class, and how it's used. Another helpful tutorial is here. Commented Apr 6, 2021 at 12:46
  • 1
    The awaiting thread has a SynchronizationContext, so it will return to that thread when the Task.Run is ready. no need to invoke anything. Commented Apr 6, 2021 at 13:11

1 Answer 1

7

how best to implement updating the interface from this method every iteration of the For loop. Using the progress bar, for example.

This is what IProgress<T> is for.

On a side note, you'll find your code is cleaner if you call methods using Task.Run instead of *implementingthem usingTask.Run`.

public partial class MainWindow : Window
{
  private List<int> Run(int par, IProgress<int> progress)
  {
    List<int> list = new List<int>();
    for (int i = 0; i < par;  i++)
    {
      // some code, that takes quite a long time
      Thread.Sleep(500); 
      list.Add(i);
      progress?.Report(i);
    }
    return list;
  }
    
  private async void StartBtn_Click(object sender, RoutedEventArgs e)
  {
    var progress = new Progress<int>(report => /* Do something with report */);
    var list = await Task.Run(() => Run(5, progress));
    label.Text = list.Count.ToString();
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.