Sometimes there are functions you want your program to perform in the background while you are busy doing other things. For example, if you are building a picture viewer application you may not want to wait until thumbnails are generated before getting on with the business of viewing the pictures. If you have ever used the '>FastStone Image Viewer you will have noticed the progress bar at the bottom of the screen when browsing to a new folder. That bar shows the progress of a background thread which is busy scanning the current folder. If you try to change the sort order of files during the scan you will get the message Background thread is busy scanning the current folder. Try again later.
Jan 7, 2017 - NET BackgroundWorker processing code on another thread and using. The BackgroundWorker and ProgressBar are available from the. To support this self-containment and communicate with the UI thread (to update the.
Implementing background threads can be easily done (but with a couple of gotchas). I hope this tutorial will be enough to get you started.
Development Environment: vb.net 2010 Development Platform: Windows 7 Pro (32 bit)
The following form will be used in the tutorial:
The objects are as follows:
This example will run a background thread for 30 seconds. Progress of the thread will be shown by three different indicators. A progress bar will show the progress graphically. Two labels will be updated with numeric values. One label will be updated by the foreground (main) thread and the other by the background thread.
It is worth noting that the only code that executes in the background is the handler for the DoWork event. This is important to note for two reasons:
Controls defined in the main thread cannot be modified from any other thread. Any changes to a control must be done through a delegate.
Modification of other resources (user defined objects, variables, etc.) must be carefully managed to avoid deadlocks (when two threads try to change the same object at the same time). Learning how to avoid conflicts is beyond the scope of this tutorial. You can find more information on this by '>Googling Thread Synchronization with Semaphores.
In order for background threads to be really useful they have to have some way of communicating with the foreground thread. There are several ways this can be done.
The background thread can report progress (as an integer value representing a percentage from 0 to 100).
The background can signal when it has completed (this is done automatically) by raising an event.
The foreground thread can check whether or not a background thread is active by calling its IsBusy method.
The background thread can directly modify variables in the foreground thread.
The last method should be used with caution. You want to ensure that both threads are not trying to modify the same variable at the same time. That's the first 'gotcha'.
We are going to declare two things at the class level. The first is the number of seconds we want the background thread to run. The other is something called a delegate (we'll discuss that later).
Now let's examine the Subs that will make up our application. The first is the event handler for form load. This sets up the initial configuration. Some of the properties could easily be set at design time but by setting them in the form load I don't have to describe the objects in as great detail. We are also going to be setting and clearing the Enabled property of the buttons to ensure that they are only clicked when appropriate. The form load event looks like
If your background thread does not need to report progress then you can set WorkerReportsProgress to False and just rely on the RunWorkerCompleted event to tell you when the thread is done.
Now let's look at the code behind the Start and Stop buttons.
All that is necessary to start the background thread is to call RunWorkerAsync. Stopping the thread is a little trickier. First you want to ensure that the thread is actually active. Also, the thread has to be capable of being cancelled. This was set at form load by setting WorkerSupportsCancellation to True.
Before we get to the actual DoWork part, let's look at the handler to update the progress bar. The background thread reports back to the main thread by calling its ReportProgress method. The single parameter is an integer value that represents the percentage complete. ReportProgress triggers the ProgressChanged event in the main thread. We are going to do two things. We will set the Value property of the progress bar as well as the Text property of lblFGStat. For this example the code looks like
The background thread will raise the RunWorkerCompleted event when it completes. All we really need to do here is update the status label and enable/disable some buttons.
Before we get to the DoWork code, let's talk about the second 'gotcha'. If you try to modify a foreground thread control from a background thread you will get something like
In order to modify foreground controls (again, to be done with caution) you have to use something called a delegate. This example has two status labels, lblFGStat and lblBGStat. The first is updated directly by the foreground thread. The latter is updated by the background thread using the delegate. You start by creating a Sub to do the update. The Sub will check to see if is being run in the foreground or background thread. The control's InvokeRequired returns True if it is running in a background thread. In this case you must access the control through the delegate. For the sake of clarity, I name the delegate the same as the referenced Sub by prefixing with 'dlg'. So the delegate for UpdateStatus is dlgUpdateStatus. The code looks like
You can call UpdateStatus from any thread and it will use the delegate as required. All that leaves us now is the actual code in the background thread. In this example we are using a loop. Because we want to be able to cancel the thread on demand we have to repeatedly check if a cancel has been requested. If so, all we have to do is set the e.Cancel flag and exit. If a cancel has not been requested then we trigger the ReportProgress event with a percentage completed value, and call UpdateStatus (which will use the delegate) to update lblBGStat. If we get to the End Sub then the RunWorkerCompleted even will be triggered.
So that is the entire example. Just in case any code slipped through the cracks (and to make it easier to copy all the code) here is the entire code in one chunk.
P: n/a
Hello all Yes I know its been done before, but something silly is killing me on this. I have the standard progress bar and worker thread scenario with progress of the worker thread being fed back to the main UI and displayed on the progress bar. I have a delegate and am using BeginInvoke. But the progress bar is not updating. I have simplified my code below(and also built and tested this code). Basic form1 with progress bar and button nothing else. -------------------------------------------------------------------------------------------- Imports System Imports System.Collections.Generic Imports System.Text Imports System.Threading Imports System.IO Public Class Form1 Dim worker As System.Threading.Thread ' Thread Dim worker_obj As New worker_class ' Object from worker class Public Sub New() Me.InitializeComponent() 'ProgressBar1 ProgressBar1.Name = 'ProgressBar1' ProgressBar1.Maximum = 100 ProgressBar1.Value = 10 End Sub Sub UpdateProgressDisplay(ByVal Value_for_progress_bar As Integer) ProgressBar1.Value = Value_for_progress_bar Application.DoEvents() End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click worker = New Thread(AddressOf worker_obj.DoRemoteCommunications) ' Now actually start the comms thread. worker.Start() End Sub End Class Public Class worker_class ' Set up delegate for assync function call. -------------------------------- Public Delegate Sub Async_Update_Progress_caller(ByVal Value_for_progress_bar As Integer) Public Sub DoRemoteCommunications() Console.WriteLine('Comms worker thread started.....') ' Set up delegate to allow asynchronous calls between threads. Dim caller As New Async_Update_Progress_caller(AddressOf Form1.UpdateProgressDisplay) ' Initiate the asynchronous call. Dim result As IAsyncResult result = caller.BeginInvoke(100, Nothing, Nothing) Console.WriteLine('Progress value 25 passed ') Thread.Sleep(3000) Console.WriteLine('Comms worker thread Finished.') End Sub End Class -------------------------------------------------------------------------------------------- Many thanks for any help. Denis _______________________ http://www.CentronSolutions.com