The new addition of async
and await
have already created buzz in the city with the superior language support of calling asynchronous code that looks pretty synchronous. There are two keywords that has been introduced to handle this behavior. The async is a specifier which directs the compiler to orchestrate automatically during the compilation to change its behavior and with the use of contextual keyword await inside an async method it makes the life of a regular programmer really easy to create more responsive code.
With WPF, the asynchronous code writing has always given lot of grief to the programmers. When dealing with cross thread data updates, we need to keep track of Dispatcher thread and call the UI updates only through Dispatcher. The complex calls to Dispatcher had been a nightmare to people as they need to more and more rely on closures to handle program flow and for a new developer it becomes that more difficult to keep track on the sequence on which the program is getting executed.
As the new API is damn simple, it made the WPF to support it as well. The first thing that has been introduced to support the async update is the introducion to new method Invoke and InvokeAsync to the Dispatcher. When calling Dispatcher, if you are not using CPU bound calls, you can use Dispatcher.Invoke or InvokeAsync directly to handle asynchrony.
Let us create a WPF Application and put a button on it. We call it as btnDispatcher
<Grid> <Button x:Name="btnDispatcher" Content="Start Dispatch" Click="btnDispatcher_Click" /> </Grid>
When the btnDispatcher_click
is called, we are going to call an async method using Dispatcher.InvokeAsync
.
private async void btnDispatcher_Click(object sender, RoutedEventArgs e) { await TestNewDispatcherAsync(); } private async Task TestNewDispatcherAsync() { var doSomething = await Dispatcher.InvokeAsync<Task<string>>(DoSomething); var result = await doSomething; MessageBox.Show(result); } private async Task<string> DoSomething() { await Task.Delay(1000); return "hi"; }
Here the method btnDispatcher_click
is marked as async, so it can await on a task. The new method TestNewDispatcherAsync
is also an Async
method which you can await. The Dispatcher.InvokeAsync
is also awaitable and hence based on the return type of DoSomething
method,you can await on that method. Even as the return value of DoSomething is a Task<string>, it can in turn again await to get the actual result.
Thus Dispatcher
allows to dispatch methods on an UI thread even without the method being marked as async.
If we have a method DoSomethingElse()
like this
private string DoSomethingElse() { return "Hi"; }
You might have also called it using
string result = await this.Dispatcher.InvokeAsync<string>(DoSomethingElse);
As the InvokeAsync supports async, you can also make use of Invoke method which is similar but the only difference is it blocks the UI thread when the method is called.
As any asynchronous code must be made in such a way that it supports cancellation, you can also pass CancellationToken
to an Dispatcher.InvokeAsync
method to cancel the call. Similar to what we use in other cases, we can cancel manually using CancellationToken
.
CancellationToken token; private async Task TestNewDispatcherAsync() { CancellationTokenSource tokensource = new CancellationTokenSource(1000); token = tokensource.Token; var doSomething = await Dispatcher.InvokeAsync<Task<string>>(DoSomething, System.Windows.Threading.DispatcherPriority.Normal, token); tokensource.Cancel(); var result = await doSomething; MessageBox.Show(result); } private async Task<string> DoSomething() { await Task.Delay(1000); if (token.IsCancellationRequested) return "cancelled"; return "hi"; }
Here the CancellationTokenSource
is used to create a CancellationToken
which has been passed with DoSomething
. As we
placed 1 second delay for cancellation
, it will call DoSomething
and wait after 1 second it will automatically get the
CancellationToken
as CancelRequested
. Rather you can also use tokenSource.Cancel to manually register a cancel on the
method.
By checking CancellationToken
before running any line, you can create a logic that breaks when Cancellation is registered.
I hope this post comes helpful.
Thank you for reading