1
\$\begingroup\$

In researching the new .NET Async and Await keywords in .NET 4.5, I created a simple example showing how to update a progress bar and a label while an async function is running. I also included how to cancel the process while it is taking place.

To use the code below, create a Windows form and include two buttons:

  1. Button1 = start button
  2. Button2 = stop button

Also add a progress bar called ProgressBar1 and a label called Label1.

A few things to note:

  1. The functions use ASYNC and AWAIT "all the way down" from the initial button click to the final VB function that supports asynchronous support;

  2. Note the use of the cancellationtokensource to signal that we want to cancel things;

  3. The final asynchronous VB function we use is WebClient.DownloadStringTaskAsync(). This is arbitrary, and is used for example purposes only.

Please let me know if you have any questions or problems with this code.

' 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 Button1_Click(sender As Object, e As EventArgs) Handles Button1.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 Button2_Click(sender As Object, e As EventArgs) Handles Button2.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
Mathieu Guindon
75.5k18 gold badges194 silver badges467 bronze badges
asked Feb 13, 2014 at 18:03
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Why not name Button1 as StartButton and Button2 as StopButton? \$\endgroup\$ Commented Feb 13, 2014 at 18:06
  • \$\begingroup\$ Are these comments in your actual code or you added them in to the reviewers' attention? Comments can also be part of a code review, if they're not in your actual code I'd recommend you remove them from the code blocks and include that context in your question instead - even if it means breaking up your code block into multiple ones. See this question for an example ;) \$\endgroup\$ Commented Feb 13, 2014 at 18:12
  • \$\begingroup\$ Thank you for your feedback. Good catch - I noted too the issue with Button1 and Button2 as well. Also, the comments are simply there to explain what is happening. The reason I put this example together is that when I looked online for examples of how to update a progress bar, they almost all used BackgroundWorker. However, with .Net 4.5, I think the async and await methods are a bit easier to use. \$\endgroup\$ Commented Feb 13, 2014 at 18:25

1 Answer 1

3
\$\begingroup\$

The final asynchronous VB function we use is WebClient.DownloadStringTaskAsync(). This is arbitrary, and is used for example purposes only.

This indicates to me that you should think about making this reusable, so that when you need to use the progress bar somewhere else, you don't need to copy & paste the code.


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

This is way too verbose. What's wrong with just the following line?

myProgress = New Progress(Of Integer)(AddressOf ReportProgress)

You don't need to comment every single thing you do, that's obvious from the code.


You should disable the button that doesn't make sense at the moment. This is especially important for the StartButton, because right now, the user can start the download multiple times.


Dim myString As String = ""
' code that doesn't use myString
myString = ...
Return myString

There is no need to declare the variable early or to set it to "". Actually, there is no need to declare the variable at all, you can just return the expression directly.


Names like Label1 and myInt are very unhelpful. Use descriptive names like ProgressLabel (though that's not great either) and stepNumber.

answered Feb 18, 2014 at 16:40
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.