In a previous article on async and await, I showed a very simple example of how to run some code asynchronously. Then in the 2nd article I showed an example of updating the user interface in the main thread from an async method.

The code below (from the previous article) would execute a long running task which in this case counts to 5,000,000. As the task was running, on a set interval, the UI would be updated. This effectively decoupled the running of the task from the updating of the UI. You could have the task update the UI every 10ms, or you could update every 5 seconds. It really depends on what you are trying to do.

using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsAsync { public partial class Form1 : Form { private readonly SynchronizationContext synchronizationContext; private DateTime previousTime = DateTime.Now; public Form1() { InitializeComponent(); synchronizationContext = SynchronizationContext.Current; } private async void ButtonClickHandlerAsync(object sender, EventArgs e) { button1.Enabled = false; var count = 0; await Task.Run(() => { for (var i = 0; i <= 5000000; i++) { UpdateUI(i); count = i; } }); label1.Text = @"Counter " + count; button1.Enabled = true; } public void UpdateUI(int value) { var timeNow = DateTime.Now; if ((DateTime.Now - previousTime).Milliseconds <= 50) return; synchronizationContext.Post(new SendOrPostCallback(o => { label1.Text = @"Counter " + (int)o; }), value); previousTime = timeNow; } } }

A reader on Reddit suggested that you can write this code in a much more succinct way as shown below. The code is much simpler to see what’s going on, but the behaviour is slightly different. In this example, the code similarly counts upto 5,000,000 and updates the UI label. The await statement here will correctly restore the synchronisation context to update the UI thread which means you don’t have to deal with it manually (I didn’t realise that at the time). To enable the asynchrony of the task in this example we need to have a Task.Delay(1) as we are not using any other asynchronous objects in .NET for file or DB access for example.

private async void ButtonClickHandlerAsync(object sender, EventArgs e) { button1.Enabled = false; for (var i = 0; i <= 5000000; i++) { label1.Text = "Counter " + i; await Task.Delay(1); } button1.Enabled = true; }

The reason the behaviour is different in this case is that the Task.Delay actually delays the method which slows down the counter to 5,000,000 whereas in the original example, the updating of the UI was interval based which didn’t affect the running speed of the original method.

As an example I tweaked the example to count to 5000 instead and timed both versions with the StopWatch timer in .NET. The timing results were as follows :

My original code : 0.8 seconds.

: 0.8 seconds. Shorter version : 1 minute 22 seconds.

As you can see that’s quite a difference. So, to summarise, both versions do roughly the same thing, yet one has more code than the other. The original version decouples the timing of the UI updates from the purpose of the actual task, where-as the shorter and clearer version introduces a delay.

At the end of the day, you need to decide what matters more to you. As with anything in software development, there are many different ways of doing the same thing.