Home > API General > I’m going to sing the doom song now -OR- Staying responsive during a long running process in VB

I’m going to sing the doom song now -OR- Staying responsive during a long running process in VB


Many times in one’s life, one must stop and seek guidance. Whether it is looking for more information or factoring the 643rd Fibonnacci number one will stop what one is doing causing everything around to freeze, much to the annoyance of the impatient user. I am talking, of course about backgrounding long running tasks in Visual Basic.

Backgrounding tasks is a pain. Suddenly, the programmer must relinquish control of program flow to the computer’s task scheduler. Many things can and quite unexpectedly will go wrong. Its like sitting down when someone else has grabbed the chair that was just behind you. I digress; This blog post aims to supply a simple pattern to follow when a program needs to do something that takes a long time (in the user’s mind, any way).

Take the following simple example. The form is designed simply with a text box named TextBox1 and a button named Button1. Here is the logic code:

Imports System.Threading
Public Class Form1
     Public Sub New()
         ' This call is required by the designer.
         InitializeComponent()
         TextBox1.ReadOnly = True
     End Sub
    Private Sub Button1_Click(sender As Object, _
                               e As System.EventArgs) _
                           Handles Button1.Click
         TextBox1.Text = "processing ..."
         TextBox1.Text = longRunningFunction()
     End Sub
    Private Function longRunningFunction() As String
         Thread.Sleep(5000)
         Return "longRunningFunction() completed"
     End Function
End Class

Quite simply, the program sets the text box to the value returned from the longRunningFunction. Unfortunately, this function takes over 5 seconds to return! The entire form is frozen the entire time. The user continues hammering at the button trying to get a response, then tries moving, and finally closing the window. As the form again begins processing events, it jumps and hangs, jumps and hangs until it finally disappears. How frustrating. (Sure, we could disable the button before the function call and enable it after… but that wouldn’t very well illustrate my point, the form still does nothing!)

Using a background worker allows us to launch the function and continue on serving the user (that ought to make CLU fume). To use a background worker, create a background handler and two Sub methods. One will handle the background worker’s DoWork event. The other will handle the RunWorkerCompleted event.

    Dim WithEvents bg As New BackgroundWorker
    Private Sub longRunningFunction(ByVal sender As Object, _
                                    ByVal e As DoWorkEventArgs) _
                                Handles bg.DoWork 
    Private Sub setResult(ByVal sender As Object, _
                           ByVal e As RunWorkerCompletedEventArgs) _
                                   Handles bg.RunWorkerCompleted

The thread is provided an object in the DoWorkEventArgs called result in which the method can shove anything it needs to provide the callback method (which runs on the parent thread). The final result of this makeover leaves our code as follows. It is certainly more complicated, but the user will now never have to wait on our longRunningFunction.

Imports System.Threading
Imports System.ComponentModel
Public Class Form1
    Dim WithEvents bg As New BackgroundWorker
    Public Sub New()
         ' This call is required by the designer.
         InitializeComponent()
         TextBox1.ReadOnly = True
     End Sub
    Private Sub Button1_Click(sender As Object, _
                               e As System.EventArgs) _
                           Handles Button1.Click
         TextBox1.Text = "processing ..."
         Button1.Enabled = False
         bg.RunWorkerAsync()
     End Sub
    Private Sub longRunningFunction(ByVal sender As Object, _
                                     ByVal e As DoWorkEventArgs) _
                                 Handles bg.DoWork
         Thread.Sleep(5000)
         e.Result = "longRunningFunction() completed"
     End Sub
    Private Sub setResult(ByVal sender As Object, _
                           ByVal e As RunWorkerCompletedEventArgs) _
                                   Handles bg.RunWorkerCompleted
         TextBox1.Text = e.Result
         Button1.Enabled = True
     End Sub
End Class
Categories: API General
  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: