ProgressBar and threading

InertiaM

Well-known member
Joined
Nov 3, 2007
Messages
663
Location
Kent, UK
Programming Experience
10+
OK, I admit - I'm confused :confused:

I'm trying to write an upload function to copy a database from my desktop to a Pocket PC. I wanted to display a progressbar to show how much it had uploaded, but the progressbar doesnt change at all :mad: The method "CopyFileToDevice" doesnt give any events, so I have had to try and calculate the upload time and display the progressbar based on elapsed time.

VB.NET:
Imports OpenNETCF.Desktop.Communication
Imports System.ComponentModel
Imports System.Threading

Public Class Form1

    Private rPocketPC As RAPI = New RAPI

    Private WithEvents TransferWorker As BackgroundWorker = New BackgroundWorker

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        rPocketPC.Connect()
        If Not rPocketPC.Connected Then Exit Sub

        TransferWorker.WorkerReportsProgress = True
        TransferWorker.WorkerSupportsCancellation = True
        ProgressBar1.Value = 0
        ProgressBar1.Visible = True
        '10,625,024 in 45691ms
        TransferWorker.RunWorkerAsync(10625024)
        Application.DoEvents()

        'UPLOAD FUNCTION GOES HERE
        MessageBox.Show("UPLOAD")
        'rPocketPC.CopyFileToDevice("c:\factory2.sdf", "\Storage Card\factory2.sdf")


        rPocketPC.Disconnect()
        rPocketPC.Dispose()
        'ProgressBar1.Visible = False
    End Sub

    Private Sub TransferWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles TransferWorker.DoWork
        Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
        e.Result = CalculateUploadTime(CType(e.Argument, Long), worker, e)
    End Sub

    Function CalculateUploadTime(ByVal FileSize As Long, ByVal worker As System.ComponentModel.BackgroundWorker, ByVal e As DoWorkEventArgs) As Long
        'TODO: calculate upload time based on file size
        Dim iTimer As Integer = 0
        While iTimer < 200
            iTimer += 1
            worker.ReportProgress(Convert.ToInt32((iTimer / 200) * 100))
            Threading.Thread.Sleep(100)
        End While
        worker.CancelAsync()
    End Function

    Private Sub TransferWorker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles TransferWorker.ProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
        Application.DoEvents()
    End Sub

    Private Sub TransferWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles TransferWorker.RunWorkerCompleted
        ProgressBar1.Visible = False
    End Sub
End Class

With the Messagebox, everything works fine - the progressbar displays, moves for 20 seconds and hides just as I would expect. If, however, I replace the messagebox line with the CopyToDevice line, the progressbar doesnt start but does hide at the end of 20 seconds.

Any suggestions please :confused:
 
CopyFileToDevice is blocking the main thread (UI Thread).

MessageBox.Show doesn't block the UI Thread. I'm not sure but I think it runs aync on other thread internally.

While Do_Work is on a new thread, TransferWorker_ProgressChanged is invoking back onto the UI thread. But it has to wait for the UI thread which is been blocked by you;re copy function.

The easist for you is to us another Worker for teh Copy stuff.
 
Working fine now - many thanks :D
 
Hi,
Did you ever finish your calculateuploadtime function? I have been looking for a way to use a progress bar to copy files over to wm5 with openetcf.desktop but I guess the file copy is a synchronous so their is no update to its progress. Your idea of calculating the time is something I hadn't thought of.
Any help is appreciated.
Thanks,
jdc4357
 
I *think* I finished it, but I dont use the device any more (found a better way :))

However, here's my last version of the code. It still needs some tidying and probably some error checking as well, but I hope it helps :)

VB.NET:
    Private WithEvents ProgressBarWorker As New BackgroundWorker

    Private Sub ProgressBarWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles ProgressBarWorker.DoWork
        Dim worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
        e.Result = CalculateUploadTime(CType(e.Argument, Long), worker, e)
    End Sub

    Private Sub ProgressBarWorker_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles ProgressBarWorker.ProgressChanged
        ProgressBar1.Value = e.ProgressPercentage
        Application.DoEvents()
    End Sub

    Private Sub ProgressBarWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles ProgressBarWorker.RunWorkerCompleted
        ProgressBar1.Visible = False
    End Sub

    Function CalculateUploadTime(ByVal RequiredFileSize As Long, ByVal worker As System.ComponentModel.BackgroundWorker, ByVal e As DoWorkEventArgs) As Long
        'TODO: calculate upload time based on file size
        '22,384,640 in 57439ms

        Dim iThreadSleep As Integer = 100
        Dim dFactor As Double = 0
        dFactor = 0.002566000614707228 '57439 / 22384640
        Dim lFactored As Long = Convert.ToInt64((RequiredFileSize * dFactor) / iThreadSleep)

        'Debug.Print("Required size = " & RequiredFileSize.ToString)
        'Debug.Print("lFactored = " & lFactored.ToString)

        Dim iTimer As Long = 0
        While iTimer < lFactored
            iTimer += 1
            worker.ReportProgress(Convert.ToInt32((iTimer / lFactored) * 100))
            Threading.Thread.Sleep(iThreadSleep)
        End While
        worker.CancelAsync()
    End Function

    Private WithEvents UploadWorker As New BackgroundWorker

    Private Sub UploadWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles UploadWorker.DoWork
        Dim stpLength As New Stopwatch
        stpLength.Reset()
        stpLength.Start()
        dRAPI.CopyFileToDevice("c:\database.sdf", "\Storage Card\databases\database.sdf", True)
        stpLength.Stop()

        'Debug.Print("Actual time taken :- " & stpLength.ElapsedMilliseconds.ToString)
    End Sub

    Private Sub UploadWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles UploadWorker.RunWorkerCompleted
        ProgressBar1.Visible = False
    End Sub

    Public Sub AddInfoText(ByVal whatText As String, Optional ByVal AtBeginning As Boolean = True)
        If AtBeginning = True Then
            txtInfo.Text = whatText & Environment.NewLine & txtInfo.Text
        Else
            txtInfo.Text &= Environment.NewLine & whatText
        End If
        Application.DoEvents()
    End Sub

and then the code to execute :-

VB.NET:
        Dim f As New IO.FileInfo("c:\database.sdf")
        Dim lFileSize As Long = f.Length

        AddInfoText("Copying database to device...")
        Application.DoEvents()


        ProgressBarWorker.WorkerReportsProgress = True
        ProgressBarWorker.WorkerSupportsCancellation = True
        ProgressBar1.Value = 0
        ProgressBar1.Visible = True
        ProgressBarWorker.RunWorkerAsync(lFileSize)
        Application.DoEvents()


        UploadWorker.WorkerReportsProgress = False
        UploadWorker.WorkerSupportsCancellation = False
        UploadWorker.RunWorkerAsync()
        Application.DoEvents()

        While UploadWorker.IsBusy = True
            Thread.Sleep(100)
            Application.DoEvents()
        End While

        AddInfoText("Database successfully copied.")
        Application.DoEvents()
 
Hi,
Thanks for the quick response and code. Works great. I have one question...

dFactor = 0.002566000614707228 '57439 / 22384640

I have played with the dFactor value to get the progress bar pretty close. What are the numbers 57439 and 22384640 represent. I figure your calculating file size and throughput.

thanks again,
jdc4357
 
VB.NET:
        'TODO: calculate upload time based on file size
        '22,384,640 in 57439ms

        ......

        dFactor = 0.002566000614707228 '57439 / 22384640

Time a file of known size, and then calculate your factor using the file size in bytes and time in milliseconds :) It isnt perfect, but it's a decent approximation :)
 
Back
Top