Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using async/await with Dispatcher.BeginInvoke()

I have a method with some code that does an await operation:

public async Task DoSomething() {     var x = await ...; } 

I need that code to run on the Dispatcher thread. Now, Dispatcher.BeginInvoke() is awaitable, but I can't mark the lambda as async in order to run the await from inside it, like this:

public async Task DoSomething() {     App.Current.Dispatcher.BeginInvoke(async () =>         {             var x = await ...;         }     ); } 

On the inner async, I get the error:

Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type.

How can I work with async from within Dispatcher.BeginInvoke()?

like image 395
Gigi Avatar asked May 03 '14 09:05

Gigi


People also ask

What is dispatcher BeginInvoke?

BeginInvoke(DispatcherPriority, Delegate, Object) Executes the specified delegate asynchronously at the specified priority and with the specified argument on the thread the Dispatcher is associated with.

Does async await use thread pool?

The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.

What is dispatcher invoke in C#?

Invoke(Action, DispatcherPriority) Executes the specified Action synchronously at the specified priority on the thread the Dispatcher is associated with. Invoke(Action) Executes the specified Action synchronously on the thread the Dispatcher is associated with.

How does async await work in Web API?

We add an async keyword to the method signature, modify the return type by using Task , and we use the await keyword when we call the GetAllCompanies awaitable method. The rest of the code – the mapping part, the logging part, and the return of the result – will be executed after the awaitable operation completes.


1 Answers

The other answer may have introduced an obscure bug. This code:

public async Task DoSomething() {     App.Current.Dispatcher.Invoke(async () =>     {         var x = await ...;     }); } 

uses the Dispatcher.Invoke(Action callback) override form of Dispatcher.Invoke, which accepts an async void lambda in this particular case. This may lead to quite unexpected behavior, as it usually happens with async void methods.

You are probably looking for something like this:

public async Task<int> DoSomethingWithUIAsync() {     await Task.Delay(100);     this.Title = "Hello!";     return 42; }  public async Task DoSomething() {     var x = await Application.Current.Dispatcher.Invoke<Task<int>>(         DoSomethingWithUIAsync);     Debug.Print(x.ToString()); // prints 42 } 

In this case, Dispatch.Invoke<Task<int>> accepts a Func<Task<int>> argument and returns the corresponding Task<int> which is awaitable. If you don't need to return anything from DoSomethingWithUIAsync, simply use Task instead of Task<int>.

Alternatively, use one of Dispatcher.InvokeAsync methods.

like image 178
noseratio Avatar answered Sep 17 '22 07:09

noseratio