1

I am trying to update 2 labels and 2 progress bars on the UI. However it does not work, the form just freezes and nothing happens until the saving is over. In windows forms I am used to using Invoke and making it update. How can I achieve updating in WPF?

Thanks!

public void EncryptFiles(string saveFileLocation, string saveFileTitle, string saveFileExtension)
{

    using (ZipFile zip = new ZipFile())
    {


        zip.Password = passwordField1.Password;
        zip.Encryption = EncryptionAlgorithm.WinZipAes256;
        foreach (File file in dataStorage.listOfFiles)
        {

            zip.AddFile(file.fileLocation, String.Empty);
        }
        zip.SaveProgress += SaveProgress;


        zip.Save(System.IO.Path.Combine(saveFileLocation, saveFileTitle + saveFileExtension));

    }

}


public void SaveProgress(object sender, SaveProgressEventArgs e)
{
    if (e.EventType == ZipProgressEventType.Saving_Started)
    {
        System.Windows.Forms.MessageBox.Show("Begin Saving: " + e.ArchiveName);
    }
    else if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry)
    {

        labelCompressionStatus.Content = "Writing: " + e.CurrentEntry.FileName + " (" + (e.EntriesSaved + 1) + "/" + e.EntriesTotal + ")";
        labelFilename.Content= "Filename:" + e.CurrentEntry.FileName;
        progressBar2.Maximum = e.EntriesTotal;
        progressBar2.Value = e.EntriesSaved + 1;


    }
    else if (e.EventType == ZipProgressEventType.Saving_EntryBytesRead)
    {
        progressBar1.Value = (int)((e.BytesTransferred * 100) / e.TotalBytesToTransfer);  
    }
    else if (e.EventType == ZipProgressEventType.Saving_Completed)
    {
        System.Windows.Forms.MessageBox.Show("Done: " + e.ArchiveName);
    }
}
daniele3004
  • 13,072
  • 12
  • 67
  • 75
john
  • 75
  • 1
  • 1
  • 8
  • Put ProgressBar task on a Worker Thread, as explained in this sample: http://www.wpf-tutorial.com/misc-controls/the-progressbar-control/ – Alexander Bell Nov 19 '14 at 03:09
  • This answer may be USEFUL https://stackoverflow.com/questions/4253088/updating-gui-wpf-using-a-different-thread – yu yang Jian Jun 25 '20 at 13:38

3 Answers3

4
Dispatcher.Invoke(new Action(() => { 
 // code here for updating GUI
 }), DispatcherPriority.ContextIdle);

Found this and it works for me, thanks everyonne

john
  • 75
  • 1
  • 1
  • 8
3

Unless you execute your code in a separate thread, the UI will not update until you complete your method. Changing the value of progressBar1 won't end up mattering, because the changes won't be visible until after all the work completes. The easiest way to do this would probably be to assign the work of EncryptFiles to a BackgroundWorker:

BackgroundWorker bw = new BackgroundWorker() { WorkerReportsProgress = true };
bw.DoWork += EncryptFiles;
bw.ProgressChanged += ReportEncryptSaveProgress;

Then, keep reference to bw and call bw.ReportProgress() each time the task is updated, passing the percentage of completion to the method. Given that ReportProgress occurs on the UI thread, you should put your updates to your ProgressBars therein, and the user should see the progress of saving.

Note that I'm not 100% sure how you'd want to move your work into the BackgroundWorker - I'm not positive I know how the ZipFile object's events work, so you might have to work with it a bit. It might end up easier to make the BackgroundWorker a field of your class rather than trying to pass it to SaveProgress, given that I'm assuming you can't alter SaveProgress's method signature.

You could accomplish the UI updates by using the Dispatcher, but your UI will still end up totally locked for the entirety of the operation, and that's generally good to avoid.

furkle
  • 5,019
  • 1
  • 15
  • 24
  • Ahh, you're right. I assumed he was already running this on a separate thread, since he said he's done similar stuff in WinForms. – Xcelled Nov 19 '14 at 03:12
  • @Xcelled194 That's a bit of an assumption on my part, but it doesn't seem like he's on a different thread. Otherwise I expect he'd be asking about `InvalidCrossThreadAccess` and not why his UI just doesn't do anything. – furkle Nov 19 '14 at 03:14
  • Perhaps he got that error and resolved it? Though I don't know how you could resolve it *without* the Dispatcher... I guess we'll have to wait and see what the OP says. – Xcelled Nov 19 '14 at 03:18
3

Edit: My answer only applies if you're running your unzip operation on a thread that is different than the UI thread (does not have to be a background worker). Otherwise, furkle's answer is what you want.

Check out the WPF dispatcher. It's designed for this usage case, and is roughly analogous to Control.Invoke() in Winforms.

Community
  • 1
  • 1
Xcelled
  • 2,084
  • 3
  • 22
  • 40