Introduction
This article is about the new features added in C# 5.0 called “Asynchrony” and how we can use them to write asynchronous code which looks like synchronous code.
As we know, WPF applications run on the STA (Single Threaded Apartment) model. The thread which controls the UI is commonly known as the UI Thread. If we want
to perform some long running tasks then we need to use Thread
or
BackGroundWorker
and use Dispatcher to update the UI. This article will cover
how we can achieve this complexity using Asynchrony with ease.
Background
For better understanding of this article I would recommend reading on the requirements of Dispatcher, multithreading, and UI updates from
a different thread in WPF. It
also requires the knowledge of the Task
class from the Task Parallel Library. It requires Visual Studio 2012 and .NET
Framework 4.5.
Using the code
First of all let’s take an example of an application form .NET 4.0 where we need to perform some long running task on
a different thread and need to update the UI.
UI:
<StackPanel>
<Button Content="Service Call" Click="ServiceCall_Click" />
<ListView ItemsSource="{Binding Tests}" />
</StackPanel>
Code:
public delegate void UpdateUI(string message);
private void ServiceCall_Click(object sender, RoutedEventArgs e)
{
Thread asycnWork = new Thread(new ThreadStart(ServiceCall));
asycnWork.Start();
}
private void ServiceCall()
{
Thread.Sleep(2000);
Dispatcher.BeginInvoke(
new UpdateUI(this.AddToTestsCollection),
new object[] { System.Threading.Thread.CurrentThread.ManagedThreadId.ToString()}
);
}
private void AddToTestsCollection(string message)
{
Tests.Add(message);
}
As we can see, we need to create a new thread and have to marshal back to the UI every time we want to update the UI.
Let’s see the new approach with Asycn – Await
private void ServiceCall_Click(object sender, RoutedEventArgs e)
{
ServiceCallAsycn();
}
private async void ServiceCallAsycn()
{
for (int i = 0; i < 5; i++)
{
var s = await GetTestAsync(i);
Tests.Add(s);
}
}
async Task<string> GetTestAsync(int i)
{
await Task.Delay(2000);
return i.ToString() + " Call - " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
}
Let us understand the “async
” and “await
” keywords and their responsibilities.
Async: It just denotes that the method is asynchronous and it has one or more
await
inside the method. If we don’t use
any await
in the method, it will give us the warning that the method will work synchronously.
Await: The await
operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited
task completes. The task represents ongoing work.
The following sentence is the heart of Asynchrony:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler
to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task
completes, it invokes its continuation, and execution of the async method resumes where it left off.
Let us understand this sentence from our example:
When the call encounters await GetTestAsync(i)
, it will return the control back to the UI. After 2 seconds it will add the result
to the Items which will become available on the UI. Here you can see that we don’t need to use Dispatcher’s
BeginInvoke
or TaskSchedular.FromCurrentSynchronizationContext()
.
Moreover, if we run the code we will see that all the results show the same thread and hence it does not introduce any new thread itself.
Conclusion
To sum up, “Asynchrony” makes the code very much simple and looks like synchronous code. Moreover it does not introduce any new thread itself. I will try to cover
exception handling and more complex scenarios in part 2. Keep learning!!