Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / VB

Simple .Net progress bar using async/await

4.60/5 (11 votes)
18 Feb 2014CPOL3 min read 85.3K  
Using .Net's Async/Await Framework To Create ProgressBar

Introduction

For the beginning C#/VB.Net developer, one of the most frustrating (yet seemingly simple) things to add to a project is a progress bar that updates while the program does something in the background (like load files or download web pages).  To accomplish this within previous versions of .Net, you'd be prompted to use threads or a background worker.  Fortunately, with the async/await framework provided in .Net 4.5 and Visual Studio 2012, implementing this type of functionality is relatively easy.  

In the following example, I will show you how to implement a progress bar that updates in real time while we download information from the Internet and gives the user the option to cancel the process, if so desired.  

Background 

If you do a Google search for how to implement a progress bar that updates while your .Net program does something in the background, you will most likely find older code examples that use threads or the background worker.  While these examples are helpful, I found that those processes are still pretty confusing.

With the advent of .Net 4.5, things get much easier.  Using the async/await framework, it is relatively straightforward to structure your functions so that you can easily execute processes "in the background" while your GUI remains responsive.  You can also make it easy for the user to cancel a background process that has been initiated but not yet completed. 

The key here is the async/await framework.  There is a lot of good information already available online about how this works, and I recommend you read it at some point.  

From my limited experience, however, the gist of this is as follows:

  1. The key point is to define your functions with the async keyword (see example) and each function that includes the async keyword must include, somewhere in its code, the await keyword as well.
  2. As you'll see in this example, this chain of async and await goes all the wait down until we use the .Net command .DownloadStringTaskAsync  (string) which retrieves a web page and returns it in string format.  Note that we are using the .DownloadStringTaskAsync command simply as an example of an asynchronous function. You can use whatever asynchronous function your program requires. 
  3. To track the progress of your background function, you have to create and pass a Progress object. This object is used by the asynchronous function to report progress back to the function that called it. Unlike the background worker, you can report progress in terms of data types other than just integers (although that's what we use here).   
  4. To give your user the ability to cancel the process as it is ongoing, you need to create a CancellationTokenSource (and, in turn, manage the .token that is part of this source).  This is not as hard as it sounds. 

Don't get discouraged by all of these new terms.  Check out the source code that follows and see if you can follow along in terms of what the program is doing.  It's not very long, which I guess is testament to how easy it is to use this framework. 

Using the code 

To use this code, create a new Windows Form called Form1 and insert the following items:

  1. A label called 'Label1' 
  2. A progress bar called 'ProgressBar1'
  3. A button called 'btnStart' and label it 'Start' 
  4. A button called 'btnStop' and label it 'Stop' 

Your form should look something like this: 

 Next, double click on the form and replace all of the code in it with the following code: 

VB.NET
' Simple progress bar example with cancellation and label updating
' Using the ASYNC and AWAIT keywords available through .Net 4.5

' Helpful sources include:
' - http://msdn.microsoft.com/en-us/library/hh191443.aspx
' - http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx

Imports System.Net
Imports System.Threading

Public Class Form1

    Dim test As WebClient = New WebClient ' This is specific to the type of async function we're doing. Yours may be different.
    Dim myToken As CancellationTokenSource ' This is used to notify the async function that we want to cancel it.
    Dim myProgress As Progress(Of Integer) ' We use this as the vehicle for reporting progress back to our GUI thread

    Dim Counter As Integer = 0 ' This is a variable that we use to track our progress (specific to this example)

    Private Async Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
        ProgressBar1.Value = 0
        Counter = 0
        myToken = New CancellationTokenSource
        Await startProgressBar(myToken) ' Note that the signature of our startprogressbar method includes the cancellationtokensource 
    End Sub

    Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
        If Not myToken Is Nothing Then
            myToken.Cancel() ' We tell our token to cancel
        End If
    End Sub

    Public Async Function startProgressBar(ct As CancellationTokenSource) As Task

        Dim progressTarget As Action(Of Integer) ' We have to create an event handler for the function we use to report progress
        progressTarget = AddressOf ReportProgress ' We assign the handler to our specific function (see below)
        myProgress = New Progress(Of Integer)(progressTarget) ' When we initialize our progress reporter, we pass our handler to it

        For I = 0 To 9

            If ct.IsCancellationRequested = True Then
                Exit For ' We then break out of the loop
            End If

            Dim myString As String = Await RetrieveString(myProgress) ' We don't do anything with this string, just so we can run our async function

        Next

    End Function

    Public Async Function RetrieveString(ByVal myProgress As IProgress(Of Integer)) As Task(Of String)

        Dim myString As String = ""

        If Not myProgress Is Nothing Then 'If we have a valid progress object, report our progress using it
            Counter = Counter + 10
            myProgress.Report(Counter)
        End If

        myString = Await test.DownloadStringTaskAsync("http://www.cnn.com") ' This is a throwaway function - just something that uses async
        Return myString ' We are really not doing anything with the results of this function, just returning it

    End Function

    Private Sub ReportProgress(ByVal myInt As Integer)
        Label1.Text = "Step Number: " & myInt.ToString
        ProgressBar1.Value = myInt
    End Sub

End Class

As you will see, this simple program downloads the contents of the CNN.com homepage into a string 10 times in a row.  Note that we're using the .DownloadStringTaskAsync function simply as an example - you can do whatever you want, as long as it is a genuine asynchronous function. 

Points of Interest  

Feel free to share any comments, bugs, suggestions and etc. below.  I'm sure that I have a lot more to learn about using this framework.  

More information on using .Net's asynchronous framework can be found at: 

http://msdn.microsoft.com/en-us/library/hh191443.aspx 

History 

Keep a running update of any changes or improvements you've made here.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)