12,065,045 members (38,867 online)
Every time I download a file via internet browser, I see the progress information presented by the download statusbar. I wanted to have a control with the same behavior for my application development. Searching the web, I found some good sources for realizing the copy process but no control with progress information. Therefore, I started to develop my own.
I found a basic idea in the article of a web coding portal as follows:
Based on this idea, I developed the control. The control is a usercontrol that hosts a progressbar and a label control.
In the attached ZIP file, you may find a Visual Studio 2013 project with two projects inside - the project for the usercontrol and a test project. Please compile the project and then attach the DLL file (FileCopyProgress.dll) from the bin\debug folder to the Visual Studio toolbox. If done, you may use the control as usual by dropping it onto a Windows Form.
The control has some extended customer properties. Before using the control, you may set the values of these properties by code in the parent form.
|Copy From||Insert complete path with full filename you like to copy.|
|Copy To||Insert complete target path with filename of the duplication.|
|Localized Strings||These strings are displayed by the control.|
Build a format string that commands which message should be shown. Insert one or more command letters (uppercase) where the letter sequence is whatever. Use:
|Progressbar color||Choose a color for the progress bar|
|Progressbar Style||Choose a style of the progress bar|
|Show Info label||If true show it, if false hide it.|
Set this value to true to activate copy process.
I would like to concentrate on the important parts and leave away the self explaining parts to keep this article short.
In the section where the variables are declared, you will find some constants. We need them to compute the different units of the file length. Notice that we have a hierarchy from bytes to Terabytes done by a multiplication of 1024 bytes (= 1 KB).
' ## Constants Const KB As Long = 1024 Const MB As Long = KB * 1000 Const GB As Long = MB * 1000 Const TB As Long = GB * 1000 Const M As Long = 60 Const H As Long = M * 60 Const D As Long = H * 24 <Description("Localized strings"), DisplayName("Localized strings"), _ Browsable(True), Category("extendedProperties")> _ Public Property msgStrings As Array
In the section of the extended properties, we will have a look at the top of each property. The property bodies are self explaining. With "
DisplayName", you can set the Property Name as it will be shown in the property grid. This name can be different from the property name in the source code. For example, to put spaces in the shown name for better reading. With "Category", you will define a new category for a better sorting of the properties in the property grid with the built in sorting function.
Now we would like to examine the main function "CopyFile" which is called by the property "
START" if its property value is set to
TRUE (FileCopyProgress1.START = TRUE) inside an event of the parent form. For example, the click event of a button.
At the beginning, we will check if the origin file to be copied is saved at the named path (Property
COPYFROM). We do this using
System.IO function exists. Next, we check if the file exists in the target folder. If it exists, we delete it with the
Private Sub CopyFile() ' (C) This code is based on an idea of a developer published: ' http://www.vb-paradise.de/index.php/Thread/29443-Datein-kopieren-mit-Fortschritt-und-verbleibender-Zeit/ Try Cursor.Current = Cursors.WaitCursor ' check file, if exists delete it If File.Exists(COPYTO) Then File.Delete(COPYTO) End If ' check original file if exists copy it If File.Exists(COPYFROM) Then
To monitor the copy process, we would like to copy the file byte by byte. Doing it this way gives us the possibilities to compute the values of rest bytes to copy, transfer speed and remaining time.
To copy byte by byte, we need two file streams one to read the byte from the original file and the other one to write the byte to create the duplicate. We call this copying byte by byte streaming. To do this, we need a special function of .NET the filestreaming object. Before we can use it, we have to initialize the filestreaming objects.
' Open filestreams for reading original file and writing the copy fromStream = New FileStream(COPYFROM, FileMode.Open) toStream = New FileStream(COPYTO, FileMode.CreateNew)
The parameters of the filestreaming objects are filepath (
COPYFROM) and streaming mode (
COPYFROM are extended properties as described above.
One of the information that can be shown in the info label of our control is the (origin) file length. We get this value with the command
fromstream.length as a returned value in bytes. To shorten the text of the info label, we have to convert the file length in kilobytes/megabytes a.s.o. To do this, we use the declared constants.
' get file length in byte total = fromStream.Length ' convert file length to KB-MB-GB-TB If total <= KB Then msg1 = total.ToString & " Byte" ElseIf total > KB And total <= MB Then intTemp = Math.Round(total / KB, 0) msg1 = intTemp.ToString & " KB" ElseIf total > MB And total <= GB Then intTemp = Math.Round(total / MB, 0) msg1 = intTemp.ToString & " MB" ElseIf total > GB And total <= TB Then intTemp = Math.Round(total / GB, 0) msg1 = intTemp.ToString & " GB" ElseIf total >= TB Then intTemp = Math.Round(total / TB, 0) msg1 = intTemp.ToString & " TB" End If
Now we have to capture the current time from the computers system clock to use it as the base for computing the elapsed time. We will need this information to compute the remaining time we need. After this, we can start a loop for the byte by byte copying (read/write process).
' Get Time startTime = DateTime.Now Do ' copy byte by byte ' check if canceled If cancel Then fromStream.Close() toStream.Close() Exit Sub End If ' read original byte Dim read As Integer = fromStream.Read(buffer, 0, buffer.Length) ' create the copy and write the byte into the copy toStream.Write(buffer, 0, read) ' monitor read status current += read ' compute done percentage for progressbar Dim Prozent As Integer = current * 100 / total ProgressBar1.Value = Prozent ' compute time used eta = startTime.Subtract(DateTime.Now) ' compute remaining kilobytes to copy and remaining time kbRemaining = (current - total) / 1024 If eta.Seconds <> 0 Then 'KB/sec kbs = Math.Round((current / 1024) / (eta.Seconds), 2) secRemaining = kbRemaining / kbs End If
After copying with
toStream.write, we compute the percentage of the copied bytes to set the value of the progress bar. Next, we compute the time used for copying. This will give us the value for the transfer speed and leads us direct to compute the value for the remaining time. We use
math.round function because we don't want to display the values with decimal figures.
At least we go to convert the values of the copied file length, the speed and the remaining time in the same way as we had done with the origin file length just before (see above).
Now we are ready to build the
string of the info label control. We are able to choose what value may be displayed and what value may
be hidden. This is done by setting the value of the property ShowLabel. This value contains uppercase command letters TCSR. Each letter represents one value:
T = origin file length to copy C = current file length copied, S = transfer speed and R = remaining time. Example: To show the file length to copy the speed and the remaining time, you have to set the property value to: TSR.
' build message string Dim strTemp As String = "" If InStr(msgFormat, "T") Then strTemp = msg1 If InStr(msgFormat, "C") Then If strTemp <> "" Then strTemp = strTemp & " | " strTemp = strTemp & msg2 End If If InStr(msgFormat, "S") Then If strTemp <> "" Then strTemp = strTemp & " | " strTemp = strTemp & msg3 End If If InStr(msgFormat, "R") Then If strTemp <> "" Then strTemp = strTemp & " | " strTemp = strTemp & msg4 End If ' show info lblmsg.Text = strTemp
To initialize the values of the localized strings and the controls, we do this in the
New() Event of our user control. The localized strings can be changed by using the property
msgStrings. The strings are used to build the message of the info label control and as the title of the error message of the
Public Sub New() ' Dieser Aufruf ist für den Designer erforderlich. InitializeComponent() ' Transfer usercontrol property values to label control With lblmsg .Font = Me.Font .ForeColor = Me.ForeColor .BackColor = Me.BackColor .Image = Me.BackgroundImage End With ' ini message string array _msgStrings(0) = " Sec." _msgStrings(1) = " Min." _msgStrings(2) = " Hrs." _msgStrings(3) = " Days" _msgStrings(4) = "Error!" End Sub
We use the
image property of our
usercontrol to set the values of the hosted label control.