In my program I have two methods that takes a while to complete, about few minutes each. While these methods are being executed, I display a Progress Bar in a separate window which shows the progress of each method. My two methods are in a static Utility class. They look like the following:
public static class Utility
{
public static bool TimeConsumingMethodOne(object sender)
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(100);
(sender as BackgroundWorker).ReportProgress(i);
}
return true;
}
public static bool TimeConsumingMethodTwo(object sender)
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(50);
(sender as BackgroundWorker).ReportProgress(i);
}
return true;
}
}
Reading through similar questions in SO I learned that I should use BackgroundWorker and used the RunWorkerCompleted() to see when the worker completes its work. So in my Main() I used BackgroundWorer() and subscribed to the RunWorkerCompleted() method. My goal here is to run the TimeConsumingMethodOne() first (and display progress while running), then once finished, run TimeConsumingMethodTwo() and show progress again, and when that's completed output the message box (which simulates some other work in my program). My Main() looks like the following:
public partial class MainWindow : Window
{
public enum MethodType
{
One,
Two
}
private BackgroundWorker worker = null;
private AutoResetEvent _resetEventOne = new AutoResetEvent(false);
private AutoResetEvent _resetEventTwo = new AutoResetEvent(false);
private ProgressBarWindow pbWindowOne = null;
private ProgressBarWindow pbWindowTwo = null;
public MainWindow()
{
InitializeComponent();
}
private void btnRun_Click(object sender, RoutedEventArgs e)
{
RunMethodCallers(sender, MethodType.One);
_resetEventOne.WaitOne();
RunMethodCallers(sender, MethodType.Two);
_resetEventTwo.WaitOne();
MessageBox.Show("COMPLETED!");
}
private void RunMethodCallers(object sender, MethodType type)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
switch (type)
{
case MethodType.One:
worker.DoWork += MethodOneCaller;
worker.ProgressChanged += worker_ProgressChangedOne;
worker.RunWorkerCompleted += worker_RunWorkerCompletedOne;
break;
case MethodType.Two:
worker.DoWork += MethodTwoCaller;
worker.ProgressChanged += worker_ProgressChangedTwo;
worker.RunWorkerCompleted += worker_RunWorkerCompletedTwo;
break;
}
worker.RunWorkerAsync();
}
private void MethodOneCaller(object sender, DoWorkEventArgs e)
{
Dispatcher.Invoke(() =>
{
pbWindowOne = new ProgressBarWindow("Running Method One");
pbWindowOne.Owner = this;
pbWindowOne.Show();
});
Utility.TimeConsumingMethodOne(sender);
}
private void MethodTwoCaller(object sender, DoWorkEventArgs e)
{
Dispatcher.Invoke(() =>
{
pbWindowTwo = new ProgressBarWindow("Running Method Two");
pbWindowTwo.Owner = this;
pbWindowTwo.Show();
});
Utility.TimeConsumingMethodTwo(sender);
}
private void worker_RunWorkerCompletedOne(object sender, RunWorkerCompletedEventArgs e)
{
_resetEventOne.Set();
}
private void worker_RunWorkerCompletedTwo(object sender, RunWorkerCompletedEventArgs e)
{
_resetEventTwo.Set();
}
private void worker_ProgressChangedOne(object sender, ProgressChangedEventArgs e)
{
pbWindowOne.SetProgressUpdate(e.ProgressPercentage);
}
private void worker_ProgressChangedTwo(object sender, ProgressChangedEventArgs e)
{
pbWindowTwo.SetProgressUpdate(e.ProgressPercentage);
}
}
Now the problem I have is, when I use _resetEventOne.WaitOne(); the UI hangs. If I removed those two waits, both methods run asynchronously and the execution moves on and outputs the MessageBox even before those two methods complete.
What am I doing wrong? How do I get the program to finish my first BackgroundWorker and then move onto the next, and then when that's done, output the MessageBox?