0

I have troubles to make my UI work using an async method. Here is a part of my code

private async void btnDoOutput_Click(object sender, RoutedEventArgs e)
{
    /* Initiliaze */
    groupBoxConfiguration.IsEnabled = false;

    var progressIndicator = new Progress<int>();
    progressIndicator.ProgressChanged += (s,value) =>
    {
        progressExport.Value = (double)value;
        labelPercentage.Content = "Export in progress : " + value + " %";
    };
    /* do Work */

    switch (something)
    {
        case 1:
            await method(input, output, options, progressIndicator);
            break;
         default: break;
    }

    /* Finalization */  
    groupBoxConfiguration.IsEnabled = true;
}

The method is

public async static Task<string> method(string input, string output, string options, IProgress<int> progress)
{
    while(something)
    {
        //operations on input and output

        if (progress != null)
        {
            progress.Report(percentage);
        }
    }
}

When I click on my button, the UI freezes, the groupBox is still enabled, the progress is not shown until the end.

Zong
  • 6,160
  • 5
  • 32
  • 46
CedMeg
  • 11
  • 1
  • 10
    That can't be all of your code, because your method signature is invalid. `method` doesn't return anything, yet it is `Task`. Async / await is not "magically make my code async". It is "make this code, that is already async, easier to work with." I don't see anything actually asynchronous happening in your code. – cadrell0 Jun 18 '14 at 13:29
  • 1
    You'll probably get a lot out of this MSDN link on enabling progress reporting and cancellation in async methods: http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx – Daniel Mann Jun 18 '14 at 13:32
  • i think you need something like `return Task.Factory.StartNew(()=>{while(something){...}})` – Grundy Jun 18 '14 at 13:34

2 Answers2

2

I think you are completely misunderstanding how async / await actually works. All of your code is still running on the UI thread because you don't actually tell it otherwise. This means your await on method is pointless because it's going to run synchronously anyway.

The purpose of async/await is to allow the calling code the opportunity to continue processing until it hits part of the code that requires the result of the awaitable task. So in your example, you would need to change your method body to actually return an awaitable Task

public Task method(string input, string output, string options, IProgress<int> progress)
{
    return Task.Run(() => {
        while(something)
        {
            //operations on input and output

           if (progress != null)
           {
               progress.Report(percentage);
           }
        }
    });
}
James
  • 80,725
  • 18
  • 167
  • 237
  • There is no reason whatsoever to call `Invoke` before reporting progress. The whole *point* of using the `Progress` class is that it manages the task of marshaling to the UI thread on your behalf. You should also use `Task.Run` rather than `StartNew`. – Servy Jun 18 '14 at 14:22
  • @Servy fair enough, I wasn't aware that `Progress` automatically did this. I removed the example anyway it was just bloating the answer unnecessarily. – James Jun 18 '14 at 14:23
  • Also, all of your comments in `MyMethod` are wrong. `Calculating...` does *not* take place while `CalcSomething` is running. The `await` ensures that it won't run until after `CalcSomething` finishes. – Servy Jun 18 '14 at 14:24
  • Also, `CalcSomething` shouldn't be `async`. As it is, it won't compile, as you're already returning a task. You're also not awaiting anything. – Servy Jun 18 '14 at 14:25
  • @Servy The example was all wrong, syntactically & logically (I wasn't in front of an IDE). – James Jun 18 '14 at 14:34
-2

First of all please don't use static methods, especially static workers.

I believe the problem is you're still on your UI thread (I'm making some wild assumptions based on the code you've given). Try using Task<string>.Factory.StartNew(...) which should automatically invoke off the UI thread.

Note may need to use the dispatcher and invoke back onto the UI thread to get your Progress bar working.

Greg B
  • 416
  • 3
  • 12
  • 1
    The UI thread is synchronous (which is why his is freezing when he performs the work), the TPL will automatically invoke over to a background thread when you start a new Task which will keep your UI responsive. – Greg B Jun 18 '14 at 13:43