Reputation: 381
I'm using WPF and I have main thread which is GUI (wizard).
When user click Finish on wizard it open second thread which display user progress bar used in background worker.
In Main thread I doing:
MessageWithProgressBar progress = new MessageWithProgressBar();
progress.Show();
createFilesInA();
createFilesInB();
createFilesInC();
createFilesInD();
createFilesInE();
createFilesInF();
createFilesInG();
createFilesInH();
createFilesInI();
createFilesInJ();
createFilesInK();
In each createFiles method I increment by 1 the static variable called currentStep which I used it in background worker as detailed below.
In background worker I doing:
public partial class MessageWithProgressBar : Window
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
public MessageWithProgressBar()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.ProgressChanged += ProgressChanged;
backgroundWorker.DoWork += DoWork;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
}
private void DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(100);
int i = GeneralProperties.General.currentStep;
if (i > GeneralProperties.General.thresholdStep)
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = 100;
title.Content = progress.Value.ToString();
return null;
}), null);
return;
}
else
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = (int)Math.Floor((decimal)(8 * i));
progressLabel.Text = progress.Value.ToString();
return null;
}), null);
}
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = e.ProgressPercentage;
return null;
}), null);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progress.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new DispatcherOperationCallback(delegate
{
progress.Value = 100;
title.Content = progress.Value.ToString();
return null;
}), null);
WindowMsgGenDB msg = new WindowMsgGenDB();
msg.Show();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (backgroundWorker.IsBusy == false)
{
backgroundWorker.RunWorkerAsync();
}
}
}
The main thread updated variable called currentStep and the second thread used it to report on the main thread progress.
The operations of the main thread takes a few seconds (not more 15 seconds)
I have two issues:
I see on progress bar only when currentStep=2 (then the progress is 16) and then the progress is 100, and I don't see every step
At the beginning, the progress bar is freeze and it seems like it stuck.
(maybe it connects to the call progress.Show() from the main thread?)
Thanks!
Upvotes: 1
Views: 1763
Reputation: 56697
As far as I understand your code your background worker is not doing anything, really. It updates the progress once and that's it.
Also: using global static variables to communicate between a form and a background worker - ouch...
Also, you're using it wrong in my opinion. The work (CreateFilesInA
... CreateFilesInK
) should be done by the background worker - that's what it is for. As the main thread will be blocked the way you implemented it, you will not see any updates otherwise.
The usual way to implement something like this is:
DoWork
. In DoWork
, after every call to a CreateFilesInXYZ
method, call ReportProgress
to the the UI be updated.ProgressChanged
event is firedThe way you're doing it it's in no way asynchronous. So, actually, your code should look something like this:
public partial class MainWindow : Window
{
private BackgroundWorker backgroundWorker = new BackgroundWorker();
private MessageWithProgressBar progressWindow;
public MainWindow()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.ProgressChanged += ProgressChanged;
backgroundWorker.DoWork += DoWork;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
progressWindow = new MessageWithProgressBar();
progressWindow.Owner = this;
progressWindow.Show();
backgroundWorker.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
int numSteps = 11;
int currentStep = 0;
int progress = 0;
CreateFilesInA();
currentStep += 1;
progress = (int)((float)currentStep / (float)numSteps * 100.0);
worker.ReportProgress(progress);
CreateFilesInB();
currentStep += 1;
progress = (int)((float)currentStep / (float)numSteps * 100.0);
worker.ReportProgress(progress);
// All other steps here
...
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressWindow.progress.Value = e.ProgressPercentage;
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressWindow.Close();
WindowMsgGenDB msg = new WindowMsgGenDB();
msg.Show();
}
}
Please note that the above code goes into your main window! The MessageWithProgressWindow
does not contain any code. Maybe the Window_Loaded
event handler is not the right place to start the background worker, but you get the picture.
Upvotes: 2