5

I'm reallt trying to get my head around async/await and Tasks. I'm trying to get one method down so that I can use it throughout my program. Basically I have my own version of BusyIndicator that I want to display whilst work is being done. Here is a basic example;

private async void OnPageLoad(object sender, RoutedEventArgs e)
{
    var waitWindow = new PleaseWaitWindow();

    waitWindow.Show();

    await LoadCompanyContracts();

    waitWindow.Close();
}

private async Task LoadCompanyContracts()
{
    await Task.Run(() =>
    {
        Dispatcher.Invoke(() =>
        {
             //Work done here
        });
    });     
}

Even through these two methods and attempting implementing Tasks my BusyIndicator still doesn't rotate, it is displayed but is frozen so in effect I believe the UI thread is still blocked. How can I modify this piece of code to ensure that all CPU bound work is not blocking the UI thread?

5
  • Hello, do you try using void for your LoadCompanyContracts methods Commented Jul 20, 2016 at 9:03
  • @OrcusZ Hi OrcusZ - it seems that await cannot work on a method that returns void. Commented Jul 20, 2016 at 9:05
  • 3
    Dispatcher.Invoke is a fancy way of saying "please get the code inside to run on the UI thread" - so you're just doing a complicated dance and then throwing away all of that work. Commented Jul 20, 2016 at 9:13
  • async void does work as it should. You need to put the time-consuming code outside Dispatcher.Invoke() block. Only invoke for UI changes. Commented Jul 20, 2016 at 9:13
  • I've noticed that if I'm updating a ProgressBar using a IProgress<int>.Report() and there is no delay in my async task, then the GUI still appears blocked, but I think what's going on is the GUI gets too many calls to update its ProgressBar. Upon putting in await Task.Delay(100) (NOT Thread.Sleep!!) to delay for 100 ms inside of the async task, then it works and you can even unnest your inner Task.Run() and do all of your work inside of the async OnPageLoad() function. Just now found this out. Commented Jan 17, 2024 at 21:41

3 Answers 3

9

As a general rule, you shouldn't use Dispatcher at all. It's extremely common practice, but it's a commonly bad practice.

private async Task LoadCompanyContracts()
{
  await Task.Run(() =>
  {
    //Work done here
  });
  // Update UI if necessary.
}
Sign up to request clarification or add additional context in comments.

Comments

2

Don't do you work inside Dispatcher.Invoke(), because your dispatcher is associated with ui thread. Do your work inside Task and use dispatcher only for updating UI

    private async Task LoadCompanyContracts()
    {
       await Task.Run(() =>
       {
         /*Work done here
          *
          */
         Dispatcher.Invoke(() =>
         {
             //Update UI 
         });
       });     
     }

Comments

-3

After looking for some examples in my code here a solution you can try :

    private async void OnPageLoad(object sender, RoutedEventArgs e)
    {
        var waitWindow = new PleaseWaitWindow();

        waitWindow.Show();

        InitLoadCompanyContracts();

        waitWindow.Close();
    }


    private async void InitLoadCompanyContracts(){
        await LoadCompanyContracts();
    }


    private async Task LoadCompanyContracts()
    {
        await Task.Run(() =>
        {
            Dispatcher.Invoke(() =>
            {
                 //Work done here
            });
        });     
    }

I use this to have an awaitable method but out of all "graphics" methods. I don't know if is the best way to do that, but for me it's work.

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.