Why build responsive UI? Answer seems obvious that end-user should experience that application doesn’t hang often (for developers POV, a time taking background operation makes it look like hanging). So lets learn building responsive UI using Async Await keywords
Visual Studio 2012 introduced a simplified approach, async programming, that leverage asynchronous support in the .NET Framework 4.5 and the Windows Runtime. The compiler does the difficult work that the developer used to do, and your application retains a logical structure that resembles synchronous code. This is extract from MSDN
Source Code was in written Visual Studio 2015 Community Edition, WPF, C#, .NET 4.5 on Windows 7 OS. However it can be used with Visual Studio 2013/2012(any version) on Windows 8, Windows 10 also.
CodeProject
Building Responsive UI using Async Await in C#
A simple WPF application which reads 12MB text file, then loops through and returns unique words with count of its occurrences in text file. Instead of using Thread Sleep or HttpClient to demonstrate async await, I have word count kind of example.
Create time taking library “WordCountLib”
- Create blank solution naming “AsyncAwaitDemoApp”.
- Create class library naming “WordCountLib” and create C# class file “WordCountClass”.
- Copy below code containing methods “FindWordCounts” and “FindWordCountsAsync”.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace WordCountLib
{
public class WordCountClass
{
public List FindWordCounts()
{
var words = Regex.Matches(File.ReadAllText(@"D:\LongFile.txt"), @"\w+").Cast()
.Select((m, pos) => new { Word = m.Value, Pos = pos })
.GroupBy(s => s.Word, StringComparer.CurrentCultureIgnoreCase)
.Select(g => new Words { WordName = g.Key, NoOfOccurance = g.Select(z => z.Pos).Count() })
.ToList();
return words;
}
public async Task<list> FindWordCountsAsync()
{
var words = Regex.Matches(File.ReadAllText(@"D:\LongFile.txt"), @"\w+").Cast()
.Select((m, pos) => new { Word = m.Value, Pos = pos })
.GroupBy(s => s.Word, StringComparer.CurrentCultureIgnoreCase)
.Select(g => new Words { WordName = g.Key, NoOfOccurance = g.Select(z => z.Pos).Count() });
return await Task.Run(() => words.ToList());
}
}
}
- Create C# class “Words”. This is POCO class to hold words name and its occurrences. Copy below
namespace WordCountLib
{
public class Words
{
public string WordName { get; set; }
public int NoOfOccurance { get; set; }
}
}
- LongFile.txt contains text copied from http://norvig.com/big.txt ; I have copied all text twice so that file is 12MB and processing should take time. Ensure that you have file at D:\LongFile.txt or else FileNotFound exception.
Building UI using WPF
- Create WPF application “WordCount.UI”, add “WordCountLib” assembly reference so that we can call WordCountClass methods.
- Open MainWindow.xaml and copy below code. This is startup window for our WPF. Draw using toolbar not so elegant but that’s not needed.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WordCount.UI"
xmlns:WordCountLib="clr-namespace:WordCountLib;assembly=WordCountLib" x:Class="WordCount.UI.MainWindow"
mc:Ignorable="d"
Title="Async Await Demo" Height="600" Width="825" WindowStartupLocation="CenterScreen">
<button>
<label>
<label>
<label>
</label></label>
<label>
<label>
</label></label>
</label></button><button>
</button>
- Open MainWindow.xaml.cs, its code behind file for our start up window. Copy the below code.
- Method “btndwn_Click” is old school type of button click event handler for “Search Words”, it instantiate “WordCountClass”, calls “FindWordsCounts”, shows listbox and binds a list of words to listbox
- Method “btndwnasyn_Click” is old school type of button click event handler for “Search Words Async Way”, it instantiate “WordCountClass”, calls “FindWordsCountsAsync”, shows listbox and binds a list of words to listbox. Note that it has async keyword in its method signature and await keyword while “FindWordsCountsAsync”
- “Log” is very simple method to log information to screen.
- Build and run it, check out image after it loads screen.
If we carefully see, await keyword is placed in-line while calling “FindWordsCountsAsync”. It clearly indicates this method is time-consuming and will block UI thread.
using System;
using System.Windows;
using WordCountLib;
namespace WordCount.UI
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btndwn_Click(object sender, RoutedEventArgs e)
{
Log("START");
if (listBox.Visibility == Visibility.Visible)
{
listBox.Visibility = Visibility.Collapsed;
}
WordCountClass wrdSimple = new WordCountClass();
var listCount = wrdSimple.FindWordCounts();
listBox.Visibility = Visibility.Visible;
listBoxasync.Visibility = Visibility.Collapsed;
listBox.ItemsSource = listCount;
Log("Done ");
}
private async void btndwnasyn_Click(object sender, RoutedEventArgs e)
{
Log("START Async");
if (listBoxasync.Visibility == Visibility.Visible)
{
listBoxasync.Visibility = Visibility.Collapsed;
}
WordCountClass wrdSimple = new WordCountClass();
var listCount = await wrdSimple.FindWordCountsAsync();
listBoxasync.Visibility = Visibility.Visible;
listBox.Visibility = Visibility.Collapsed;
listBoxasync.ItemsSource = listCount;
Log("Done Async");
}
private void Log(string text)
{
string line = string.Format("{0:HH:mm:ss.fff}: {1}\r\n", DateTime.Now, text);
logtxtBlock.AppendText(line);
}
}
}
WPF Main Window for Async Await Demo
Testing the responsiveness of the WPF UI
- Click on button “Search Words”, try to move window, resize it. You can’t do anything as it reads the file, finds all words count and binds to list box. This is called non responsive UI or application hanging. Check out GIF image below. Notice that after it loads list box, screen window moves bit because after button click I tried to use window.
Non Responsive UI on button click
- Now run application again, click “Search Words Async Way”. Just move around window, resize it, see Log information being written. This called RESPONSIVE UI using Async Await in C#
- Just play around it by clicking buttons back and forth.
Responsive UI using Async Await
- Async methods are intended to be non-blocking operations. An await expression in an async method doesn’t block the current thread while the awaited task is running.
- The async and await keywords don’t cause extra threads to be created. Async methods don’t need multi-threading because an async method doesn’t run on its own thread.
The post Building Responsive UI using Async Await in C# appeared first on Mithunvp.com.