Showing the Progress of a Copy Process with Backgroundworker and Progressbar


Showing the progress of a copy operation is quite a common question on programming forums such as With today's article, I will shed some light on this topic for you.

Before I continue, I must explain a few of the technologies that we're going to use during the course of this article.


A delegate is simply a type that represents a reference to physical methods with the same parameter list and return type. Okay, what does that mean in simple terms? A delegate is basically a substitute for a method with the same return type and with the same signature. We make use of a delegate when we cannot access certain threads directly (as explained in this article), or when we need to ensure that managed and unmanaged code can be executed properly.

Delegates (C# Programming Guide) at MSDN has a more detailed explanation of delegates.AddHandler/AddressOf.

Here is more information on the AddressOf operator.


Here is more information on the BackgroundWorker class.

Now that you have a basic understanding of all the terms and objects you will encounter during this project, we can continue to a practical example.


Create a new Visual Basic Windows Forms project. The design should resemble Figure 1.

Figure 1: Our design


Add the required namespaces:

Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.IO

Add the following variable objects:

   Private bwCopier As New BackgroundWorker

   Private Delegate Sub ProgressChanged(ByVal info As UIProgress)
   Private Delegate Sub CopyError(ByVal err As UIError)

   Private OnChange As ProgressChanged

   Private OnError As CopyError

With the preceding code, I created a BackgroundWorker object that will be responsible for running the copy operation in the background. That is why you need the two delegates: ProgressChanged and CopyError. Lastly, I created two objects that will consume both delegates. You may have noticed that, when creating the two delegates, they refer to separate classes. Let us create them now.

UIProgress Class

Public Class UIProgress

   Public strName As String
   Public lngBytes As Long
   Public lngMaxBytes As Long

   Public Sub New(ByVal FileName As String, _
         ByVal Bytes As Long, ByVal MaxBytes As Long)
      strName = FileName
      Bytes = Bytes
      MaxBytes = MaxBytes
   End Sub

End Class

There isn't much in this class. This class is simply responsible for updating the form's interface as the copy progresses.

UIError Class

Public Class UIError

   Public strErrorMsg As String
   Public strFilePath As String
   Public drResult As DialogResult

   Public Sub New(ByVal ex As Exception, _
         ByVal FilePath As String)
      strErrorMsg = ex.Message
      strFilePath = FilePath
      drResult = DialogResult.Cancel
   End Sub

End Class

This simple class just throws an error when something goes wrong in the copy operation. Let's go on to the rest of the Form's code. Add the constructor:

   Public Sub New()


      AddHandler bwCopier.DoWork, AddressOf DoCopy
      AddHandler bwCopier.RunWorkerCompleted, _
         AddressOf WorkerCompleted

      bwCopier.WorkerSupportsCancellation = True

      OnChange = AddressOf ChangeProgress
      OnError = AddressOf ErrorThrow


   End Sub

Here, I connected the backgroundworker's event to our own methods. We will add these methods as we progress through this article.

Add the DoCopy procedure:

   Private Sub DoCopy(ByVal sender As Object, _
      ByVal e As DoWorkEventArgs)

      Dim arrExtensions As String() = _
         {"*.jpg", "*.jpeg", "*.bmp", "*.png", "*.gif"}

      Dim lstFiles As New List(Of FileInfo)

      Dim strFolderPath As String = _

      Dim diDirectory As New DirectoryInfo(strFolderPath)

      Dim lngMaxBytes As Long = 0

      For Each strExt As String In arrExtensions

         Dim fiFolder As FileInfo() = diDirectory.GetFiles(strExt, _

         For Each fiFile As FileInfo In fiFolder

            If ((fiFile.Attributes And FileAttributes.Directory) <> 0) _
               Then Continue For

            lngMaxBytes += fiFile.Length


      Dim lngBytes As Long = 0
      For Each file As FileInfo In lstFiles

            Me.BeginInvoke(OnChange, New Object() _
               {New UIProgress(file.Name, lngBytes, lngMaxBytes)})
            System.IO.File.Copy(file.FullName, "c:\temp\" + _
               file.Name, True)

         Catch ex As Exception

            Dim err As New UIError(ex, file.FullName)
            Me.Invoke(OnError, New Object() {err})
            If err.drResult = Windows.Forms.DialogResult.Cancel _
               Then Exit For

         End Try

         lngBytes += file.Length


   End Sub

Add the ChangeProgress procedure:

   Private Sub ChangeProgress(ByVal info As UIProgress)

      ProgressBar1.Value = CInt(100.0 * _
         info.lngBytes / info.lngMaxBytes)
      Label1.Text = "Copying " + info.strName

   End Sub

Add the next procedures:

   Private Sub ErrorThrow(ByVal err As UIError)

      Dim msg As String = String.Format("Error _
         copying file {0}\n{1}\nClick OK to continue _
         copying files", Err.strFilePath, Err.strErrorMsg)
      err.drResult = MessageBox.Show(msg, "Copy error", _
         MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation)

   End Sub

   Private Sub WorkerCompleted(ByVal sender As Object, _
      ByVal e As RunWorkerCompletedEventArgs)


   End Sub

   Private Sub UpdateUI(ByVal docopy As Boolean)
      Label1.Visible = docopy
      ProgressBar1.Visible = docopy

      If docopy Then Button1.Text = "Cancel" _
         Else Button1.Text = "Copy"
      Label1.Text = "Starting copy..."
      ProgressBar1.Value = 0

   End Sub

Finally, add the Button's click event:

   Private Sub Button1_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles Button1.Click
      Dim docopy As Boolean = Button1.Text = "Copy"


      If (docopy) Then bwCopier.RunWorkerAsync() _
         Else bwCopier.CancelAsync()

   End Sub


The next time you have to use copying logic within your applications, I hope you find this article useful. Until next time, cheers!

About the Author

Hannes DuPreez

Hannes du Preez is a Microsoft MVP for Visual Basic for the eighth consecutive year. He loves technology and loves Visual Basic. He has a lot of experience in .NET and loves to share his love, pain and musings about Visual Basic

Related Articles


  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date