I have been trying to implement a BackgroundWorker into my application, and so far, it has not gone well. On a new thread, I want to open up a new Form that will have a progressbar and a label to report progress, however, this is not working well. When I call ShowDialog, the application does not respond any more. Is this because my code is running from my Form1, and I am showing WorkingForm? Also, can this be implemented cleaner?
private void button14_Click(object sender, EventArgs e)
{
List<object> param = new List<object>();
object[] objectparams = new object[1];
objectparams[0] = null;
Opera opera = new Opera();
System.Reflection.MethodInfo clearOpera = opera.GetType().GetMethod("ClearOpera");
param.Add(clearOpera);
param.Add(opera);
param.Add(objectparams);
backgroundWorker1.RunWorkerAsync(param);
}
private void button2_Click_1(object sender, EventArgs e)
{
Browser.cancelPending = true;
}
private delegate void getnewform();
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
mainForm main = new mainForm();
TestURLGUI4.Form1 form = (TestURLGUI4.Form1)Application.OpenForms[0];
var variab = (bool)form.Invoke(new getnewform(main.AskForConfirmation));
List<object> param = e.Argument as List<object>;
List<object> result = new List<object>();
var method = param[0] as MethodInfo;
object[] parameters = param[2] as object[];
if (parameters[0] == null)
{
result.Add(method.Invoke(param[1], null));
result.Add(false);
}
else
{
result.Add(method.Invoke(param[1], parameters));
if (parameters.Contains(true))
result.Add(true);
}
int progress = (100 * Browser.progressValue) / Browser.progressMax;
backgroundWorker1.ReportProgress(progress);
// If the BackgroundWorker.CancellationPending property is true, cancel
if (backgroundWorker1.CancellationPending)
{
Console.WriteLine("Cancelled");
Browser.cancelPending = true;
}
e.Result = result;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
TestURLGUI4.WorkingForm form = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
form.progressBar1.Value = e.ProgressPercentage;
form.label1.Text = Browser.progressValue + "/" + Browser.progressMax;
Application.DoEvents();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
List<object> param = e.Result as List<object>;
if (e.Cancelled == false && param.Contains(true))
{
Display.DisplayURLs(param[0] as SortableBindingList<URL>);
TestURLGUI4.WorkingForm form = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
MessageBox.Show("Done");
}
else if (e.Cancelled == false && param.Contains(false))
{
TestURLGUI4.WorkingForm form = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
MessageBox.Show("Done");
}
}
public class mainForm
{
public void AskForConfirmation()
{
TestURLGUI4.Form1 form = (TestURLGUI4.Form1)Application.OpenForms[0];
var workingForm = new TestURLGUI4.WorkingForm();
workingForm.ShowDialog(form);
workingForm.DialogResult = DialogResult.None;
}
}
Edit:
Ok, I have updated my code according to the suggestions, and now, this produces a stackoverflowexception in System.Windows.Forms.dll:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
mainForm main = new mainForm();
TestURLGUI4.Form1 form = (TestURLGUI4.Form1)Application.OpenForms[0];
List<object> param = e.Argument as List<object>;
List<object> result = new List<object>();
var method = param[0] as MethodInfo;
object[] parameters = param[2] as object[];
if (parameters[0] == null)
{
result.Add(method.Invoke(param[1], null));
result.Add(false);
}
else
{
result.Add(method.Invoke(param[1], parameters));
if (parameters.Contains(true))
result.Add(true);
}
int progress = (100 * Browser.progressValue) / Browser.progressMax;
backgroundWorker1.ReportProgress(progress);
// If the BackgroundWorker.CancellationPending property is true, cancel
if (backgroundWorker1.CancellationPending)
{
Console.WriteLine("Cancelled");
Browser.cancelPending = true;
}
e.Result = result;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
TestURLGUI4.Form1 form1 = (TestURLGUI4.Form1)Application.OpenForms[0];
if (Application.OpenForms.Count >= 2)
{
TestURLGUI4.WorkingForm form2 = (TestURLGUI4.WorkingForm)Application.OpenForms[1];
form2.progressBar1.Value = e.ProgressPercentage;
form2.label1.Text = Browser.progressValue + "/" + Browser.progressMax;
Application.DoEvents();
}
else if(Application.OpenForms.Count == 1)
{
var workingForm = new TestURLGUI4.WorkingForm();
workingForm.ShowDialog(form1);
}
}
The purpose of a
BackgroundWorkeris to invoke code on another thread (not the UI thread). By callingInvokein theDoWorkmethod, you’re completely circumventing the purpose ofBackgroundWorker. Do all your UI work before you start the worker. If you need to interact with the user while the worker is working, do it in theProgressChangedhandler–it runs on the UI thread and you don’t need to useInvokeinProgressChanged.By invoking UI work in
DoWork, you run the risk of a deadlock, which will hang your program