Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# progressbar not updating

I have a ProgressBarWindow which has a progressbar and a cancel button on it which I use to report progress on file I/O. However, the UI Thread of the ProgressBarWindow and my main window both hang despite all the work being done in a backgroundworker. The progressbar is rendered, as is my main window, but does not update whilst the backgroundworker does its thing. The following code is called at the very end of the constructor of the main window:

iCountLogLinesProgressBar = new ProgressBarWindow();
iCountLogLinesProgressBar.cancelButton.Click += EventCountLogLinesProgressBarCancelButtonClicked;
iCountLogLinesProgressBar.Show();

iCountLogRecords = new BackgroundWorker();
iCountLogRecords.DoWork += EventCountLogLinesDoWork;
iCountLogRecords.ProgressChanged += EventCountLogLinesProgressChanged;
iCountLogRecords.RunWorkerCompleted += EventCountLogLinesRunWorkerCompleted;
iCountLogRecords.WorkerReportsProgress = true;
iCountLogRecords.WorkerSupportsCancellation = true;
iCountLogRecords.RunWorkerAsync(new BinaryReader(File.Open(iMainLogFilename, FileMode.Open, FileAccess.Read)));

EventCountLogLinesProgressChanged() looks like this:

private void EventCountLogLinesProgressChanged(object sender, ProgressChangedEventArgs e)
{
    iCountLogLinesProgressBar.Value = e.ProgressPercentage;
}

Here is a shortened version of ProgressBarWindow(the rest is just a couple of setters):

public partial class ProgressBarWindow : Window
{
    public ProgressBarWindow()
    {
        InitializeComponent();
        this.progressBar.Value = this.progressBar.Minimum = 0;
        this.progressBar.Maximum = 100;
    }

    public double Value
    {
        get
        {
            return progressBar.Value;
        }
        set
        {
            this.progressBar.Value = value;
        }
    }
} 

I've tried wrapping the value setter line in a dispatcher.invoke delegate but that gives me a stack overflow(I shouldn't have to have a dispatcher.invoke line anyway as backgroundworker calls ProgressChanged in the UI Thread, right?). I have checked msdn and googled but I can't seem to find anyone else with this problem.

EDIT Apologies, I did not realise my simplified code blocked the UI Thread, I get exactly the same behaviour despite using a backgroundworker so I erroneously assumed they were equivalent. I should have mentioned I was using a backgroundworker :P

like image 268
CalumMcCall Avatar asked Aug 02 '10 11:08

CalumMcCall


2 Answers

You're blocking the UI thread, so it won't re-render the UI until your loop has finished.

Move the background processing into a separate thread, and use appropriate Dispatcher calls (or BackgroundWorker) to marshal UI update calls back to the UI thread.

If your progress bar is really just meant to be a timer, you could use one of the Timer classes to update it.

EDIT: Okay, now you've changed the code, it looks okay to me. It should be thread-safe as you're only changing the UI on the UI thread. Is your background worker definitely reporting progress periodically?

like image 95
Jon Skeet Avatar answered Oct 12 '22 21:10

Jon Skeet


Listen to Jon Skeet, or you could sometimes call Application.DoEvents() to make all UI updates in the same thread.

like image 30
Alex Avatar answered Oct 12 '22 21:10

Alex