Responsiveness of your app is not just fee UI thread by implementing async. It is more that that. When a long operation is under process in your app, user sometimes wants to cancel it or pause the operation. Imagine your app processing hundreds of files or images. Such a operation can take more that few seconds and user must have option to cancel it. Canceling and pausing are very important feature for every app that implements long operations.
This blog post will present the way of using CancelationToken built in cancel feature in .NET, as well as a PauseToken custom implementation which is very similar to CancelationToken.
Original implementation of PauseToken is from the pfxteam blog which you can find here.
We will implement simple Windows Store app with cancel and pausing the async operation. The picture below shows the sample app:
As you can see when the Start Process button is clicked it begins process of processing image files. There is also ProgressRing control which shows the progress and percentage of completeness. From the right side you can see two buttons. The Cancel button cancels the operation, and pause button pauses operation until the Pause button is clicked again.
The implementation behind Process button is the folowing:
private async void btnProcess_Click(object sender, RoutedEventArgs e) { //creating cancel and pause token sources m_pauseTokeSource = new PauseTokenSource(); m_cancelationTokenSource = new CancellationTokenSource(); //get al picture from picture library var picturesFolder = KnownFolders.PicturesLibrary; var fileList = await picturesFolder.GetFilesAsync(); //set ProgressRing to active ring2.IsActive = true; try { //asynchrony process files, by passing pasue and calcel tokens await ProcessImages(fileList, m_pauseTokeSource.Token, m_cancelationTokenSource.Token); } catch (Exception) { //do nothing when somthing went wrong not when taks is canceled } finally { //make inactive ProgressRing ring2.IsActive = false; } }
Click event implementation of the Start Process button
First we create Cancel and Pause Source tokens. Gent the picture content in form of list of files. Then we call asynchonious ProcessImages method by passing list of images files, cancel and pause tokens. Process images is called within try catch finally blocks, because every cancel task throws exception.
Implementation ProcessImages async method
ProcesImage method is async method which accept cancelation and pasue token nad returns Task object.
public async Task ProcessImages(IEnumerable<StorageFile> images, PauseToken pauseToken, CancellationToken cancelToken) { double count=images.Count(); double current=0; foreach (var file in images) { //if the paise is active the code will wait here but not block UI thread await pauseToken.WaitWhilePausedAsync(); ring2Text.Text = string.Format("{0}%",(int)(100*current / count)); await ProcessAsync(file, cancelToken); current++; } ring2Text.Text = string.Format("100%"); }
In foreach loop first we await pauseToken.WaitWhilePausedAsync(); which wait if IsPause property of the Token class is true, otherwize there is no awaiting here. The next await is out Delay which takes cancelation token as parameters. When the Pause button is clicked, pauseToken is awaiting until the pause button is clicked again. In case of cancelation when the Cancel button is clicked the Cancel() method of the cancelationTokenSource is called and exception is thorwn. Then processImages method is interupted and finally blick progressring is disabled.
Pause and Cancel Click implementation are shown in the following listing:
private void btnPause_Click(object sender, RoutedEventArgs e) { m_pauseTokeSource.IsPaused = !m_pauseTokeSource.IsPaused; } private void btnCancel_Click(object sender, RoutedEventArgs e) { m_cancelationTokenSource.Cancel(); }
Complete source code can be downloaded from link below.
Thanks a lot. This helped me a lot for my work.
Thanks Bahrudin,
Just the right example to get my head around async and await. Converted to WinForm and performed a directory trawl.