ProgressBar help

Jan 4, 2010 at 2:12 PM
Edited Jan 4, 2010 at 2:15 PM

How do I update a ProgressBar to show the progress of a save operation?  I am using this code to zip a folder:

 

Using zip As ZipFile = New ZipFile()

zip.AddDirectory(

"c:\myFolder")

zip.Save("c:\temp\MyZipFile.zip")

End Using

 

Do I need to use a BackgroundWorker?  I looked at the code on the examples page but I couldn't figure out how to apply it for my case.  Thanks.

Coordinator
Jan 4, 2010 at 7:55 PM

There are two things that take some time in the example code you offered. The AddDirectory() call can take some time if you have a directory of 10,000 files or more, then the Add operation can take some time.  It involves memory operations, so it's won't take a huge amount of time, but 10,000 of anything will take some time.  The second is the Save() operation - this involves writing to the filesystem, and will take more time.

For the first, you can use an AddProgress event, for the second, you can use a SaveProgress event.  The events are just ways for DotNetZip to call your code - code you provide, as it makes progress through those operations.  A callback.  As the Save proceeds, it can call your code for every file added to the zip, for example.  If you hook into the SaveProgress event, you can update a ProgressBar from within your code.  Because the Add operation generally happens so much faster than the Save(), you likely won't need a progress event for the Add. 

Now, the question of whether you need a BackgroundWorker is somewhat independent.  It depends. 

If you have a directory of,say 1000 files totally maybe 20mb, then no, you probably won't need  a background worker. The entire Add() and Save() operation will take maybe 5 or 6 seconds, and your UI could just put an hourglass up for that time, and the user won't be terribly inconveniced. 

On the other hand if the directory is 10,000 files or more and can constitute a file of 1gb or more, then you will need a BackgroundWorker.  But not simply for the progress bar - you need a BackgroundWorker to preserve UI responsiveness while the operation occurs, and following good UI principles, you will need to provide a Cancel button to interrupt the long-running process if the user chooses to do so.  In the general case, you want to do the zipping on a BackgroundWorker.  

Anyway, there's a nice VB example that covers this - it shows how to use a SaveProgress event and a BackgroundWorker.  It's a VB project for VS2008. 

To get this you need to download the latest source snapshot at  http://dotnetzip.codeplex.com/SourceControl/changeset/view/53555 .   I had thought it was part of the regular "released" source zip, but it is not.  Not yet.  so for now, you need to go to that snapshot. Click the "Source code" tab on the dotnetzip project site, and then navigate to the example, as shown in the image here:

 The most interesting bits of code are here:

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnZipUp.Click
        Me.KickoffZipup()
    End Sub


    Private Sub KickoffZipup()
        Dim folderName As String = Me.tbDirToZip.Text
        If (((Not folderName Is Nothing) AndAlso (folderName <> "")) AndAlso ((Not Me.tbZipToCreate.Text Is Nothing) AndAlso (Me.tbZipToCreate.Text <> ""))) Then
            If File.Exists(Me.tbZipToCreate.Text) Then
                If (MessageBox.Show(String.Format("The file you have specified ({0}) already exists.  Do you want to overwrite this file?", _
                                                  Me.tbZipToCreate.Text), "Confirmation is Required", _
                                                  MessageBoxButtons.YesNo, MessageBoxIcon.Question) <> DialogResult.Yes) Then
                    Return
                End If
                File.Delete(Me.tbZipToCreate.Text)
            End If
            Me._saveCanceled = False
            Me._nFilesCompleted = 0
            Me._totalBytesAfterCompress = 0
            Me._totalBytesBeforeCompress = 0
            Me.btnZipUp.Enabled = False
            Me.btnZipUp.Text = "Zipping..."
            Me.btnCancel.Enabled = True
            Me.lblStatus.Text = "Zipping..."
            Dim options As New WorkerOptions
            options.ZipName = Me.tbZipToCreate.Text
            options.Folder = folderName
            
            _backgroundWorker1 = New System.ComponentModel.BackgroundWorker()
            _backgroundWorker1.WorkerSupportsCancellation = False
            _backgroundWorker1.WorkerReportsProgress = False
            AddHandler Me._backgroundWorker1.DoWork, New DoWorkEventHandler(AddressOf Me.DoSave)
            _backgroundWorker1.RunWorkerAsync(options)
            
        End If
    End Sub

    
    Private Sub DoSave(ByVal sender As Object, ByVal e As DoWorkEventArgs)
        Dim options As WorkerOptions = e.Argument
        Try
            Using zip1 As ZipFile = New ZipFile
                zip1.AddDirectory(options.Folder)
                Me._entriesToZip = zip1.EntryFileNames.Count
                Me.SetProgressBars()
                AddHandler zip1.SaveProgress, New EventHandler(Of SaveProgressEventArgs)(AddressOf Me.zip1_SaveProgress)
                zip1.Save(options.ZipName)
            End Using
        Catch exc1 As Exception
            MessageBox.Show(String.Format("Exception while zipping: {0}", exc1.Message))
            Me.btnCancel_Click(Nothing, Nothing)
        End Try
    End Sub

Jan 4, 2010 at 8:27 PM

So how do I set the Maximum value for my progressbar to track the AddDirectory progress?  It appears that I can't get the number of files

in the zip object until AFTER the AddDirectory process has completed.

Coordinator
Jan 4, 2010 at 8:53 PM

Well that's correct.  There's no way for the library to know how many files it will find in the directory until it finds them in the directory, if you know what I mean.

And as soon as DotNetZip finds a file in the directory, it adds the file to the archive and then invokes the AddProgress event.  so .. To drive a progress bar based on AddProgress, you would need an indefinite progress indicator.

 

Jan 4, 2010 at 9:02 PM

OK, so just to clarify ... there is no way to track the progress (percentage wise) of the AddDirectory process?  Only the Save process can be tracked?

Is there any practical purpose for the AddProgress event?

Coordinator
Jan 4, 2010 at 9:26 PM

Well sure, there's a practical purpose. I just told you.  It gives you a call for every entry.  That is its practical purpose. I take it you don't value that purpose, but that is a purpose, whether you like it or not.

I think you mean;  "is there a way to know how many entries will eventually be added as AddDirectory proceeds, so that I can drive a traditional progressbar?"

You can do this, if you know how many total entries will be added in the beginning.  One way to do this is to call Directory.GetFiles, and remember the number of files in the directory before calling AddDirectory. 

Or, pass a finite IEnumerable<String> to the AddFiles() method, and in your code you know how many items are in the IEnumerable. 

Then you can set ProgressBar.MaximumValue.