2012-08-13 61 views
0

我一直在努力实现一个BackgroundWorker到我的应用程序,到目前为止,还没有顺利。在一个新线程中,我想打开一个新的表单,该表单将包含一个进度条和一个标签以报告进度,但是,这样做效果不佳。当我调用ShowDialog时,应用程序不再响应。这是因为我的代码是从我的Form1运行的,而且我正在显示WorkingForm?此外,这可以实施更清洁?的BackgroundWorker的ShowDialog导致应用程序停止

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; 

} 
} 

编辑: 好吧,我已经根据建议更新了我的代码,而现在,这将产生在System.Windows.Forms.dll中一个stackoverflowexception:

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); 
    } 
} 
+0

让youyr生活轻松了许多。在您关闭线程之前进行确认,并完全消除Application.OpenForms的需求。这是一个几乎保证的比赛,表格可能会在您获得参考后关闭。甚至不想考虑一下你的显式索引索引可能会在应用程序发生一些变化之后留下来。 – 2012-08-13 21:15:43

+0

有人可以看看我更新的代码吗? – 2012-08-14 01:17:26

回答

4

BackgroundWorker的目的是调用另一个线程(而不是UI线程)上的代码。通过在DoWork方法中调用Invoke,您完全可以规避BackgroundWorker的目的。在启动工作人员之前,完成所有UI的工作。如果您需要与工人正在工作的用户交互,这样做在ProgressChanged处理程序 - 它运行在UI线程上,你不需要ProgressChanged使用Invoke

通过调用DoWork UI的工作,你运行一个死锁的风险,这将挂程序

0

你不能上运行的UI其他线程。必须在主线程上。

实例化UI启动新线程之前。在新线程中,您想要使用的控件上使用跨线程调用方法。看这里例如http://msdn.microsoft.com/en-us/library/ms171728.aspx

+1

除非你打算建议一个实际的解决方案,否则这会更好地发布为评论。 – ChrisF 2012-08-13 20:24:19