2014-10-05 97 views
-1

对于太长时间,我一直在尝试运行一个外部.bat文件(为某些统计处理调用R脚本),并将控制台重定向到U.I.在主线程处于活动状态时BackgroundWorker线程不会触发

我觉得我很接近,但正如我已经得到它的工作,我遇到了一个相当大的问题!也就是说:只有当主线程结束时(通过:return;),而不是Thread.Sleep或.WaitOne()等时,才会进行血腥的工作。

这是我在主线程中的代码。

string batLoc = ALLRG___.RSCRBIN_LOC + "current.bat"; 
BackgroundWorker watchboxdWorker1 = new BackgroundWorker(); 
watchboxdWorker1.DoWork += frmC.WatchboxWorker1_WatchExt; 

frmC.wbResetEvent = new AutoResetEvent(false); 
watchboxdWorker1.RunWorkerAsync(batLoc); 

//Thread.Sleep(1000*20); 
//frmC.wbResetEvent.WaitOne(); 
return; 

请注意注释掉Sleep和/或WaitOne()指令。如果我尝试并使用这些BackgroundWorker执行,但更新U.I的'事件'不会。

在我的表单的代码(以上FRMC)如下,

public void WatchboxWorker1_WatchExt(object sender, DoWorkEventArgs e) 
    { 
     string exeLoc = (string) e.Argument; 

     string arg1 = exeLoc;    
     string arg2 = ""; 

     ProcessStartInfo pStartInfo = new ProcessStartInfo(); 

     pStartInfo.FileName = exeLoc; 
     pStartInfo.Arguments = string.Format("\"{0}\" \"{1}\"", arg1, arg2); 

     pStartInfo.WorkingDirectory = Path.GetDirectoryName(exeLoc); 
     pStartInfo.CreateNoWindow = true; 
     pStartInfo.UseShellExecute = false; 

     pStartInfo.RedirectStandardInput = true; 
     pStartInfo.RedirectStandardOutput = true; 
     pStartInfo.RedirectStandardError = true; 

     Process process1 = new Process(); 

     process1.EnableRaisingEvents = true; 

     process1.OutputDataReceived += new DataReceivedEventHandler(wbOutputHandler); 
     process1.ErrorDataReceived += new DataReceivedEventHandler(wbErrorHandler); 

     process1.StartInfo = pStartInfo; 
     process1.SynchronizingObject = rtbWatchbox; 

     process1.Start(); 
     process1.BeginOutputReadLine(); 
     process1.BeginErrorReadLine(); 

     process1.StandardInput.Close(); 

     process1.WaitForExit(); 

     wbResetEvent.Set(); 

    } 

    public void wbOutputHandler(Object source, DataReceivedEventArgs outLine) 
    { 
     int x = 0; 

     if (!String.IsNullOrEmpty(outLine.Data)) 
     { 
      rtbWatchbox.AppendText(outLine.Data); 
     } 

    } 

    public void wbErrorHandler(Object source, DataReceivedEventArgs outLine) 
    { 
     int x = 0; 

     if (!String.IsNullOrEmpty(outLine.Data)) 
     { 
      rtbWatchbox.AppendText(outLine.Data); 
     } 
    } 

我的问题是 -

的wbOutputHandler和wbErrorHandler得到很好地解雇作为控制台更新 - 但只有当主如果我在主线程中使用Thread.Sleep或.WaitOne()将控制传递给BackgroundWorker(WatchboxWorker1_WatchExt),那么代码将成功运行,但wbOutputHandler和wbErrorHandler方法根本不会被触发。实际上,如果我执行Thread.Sleep(10 * 1000),那么外部程序按计划开始运行,传递10秒,然后当主UI线程退出时,我会立即得到一个大的巨大更新。

我不想让我的主线程关闭,我想在工作完成后继续在那里做东西!

[用于替代方法是一个更好的办法当然高兴]“帮我堆栈溢出,你是我唯一的希望!”

+2

您不会登录到“控制台”,而是登录到某个“RichtTextBox”右边?所以这是一个WinForms应用程序 - 然后问题是:运行UI的代码在哪里(有点像Application.Run(new Form1());')?顺便说一句:当然UI不会更新,如果你阻止它的线程... – Carsten 2014-10-05 06:35:43

+0

PS:如果你不以这种方式退出你的应用程序,你不需要阻止! – Carsten 2014-10-05 06:36:44

+0

谢谢Carsten你神奇地有帮助。 – 2014-10-06 09:40:14

回答

0

答案是将backgroundWorker放入另一个为UI线程创建的backgroundWorker中。考虑到将控制台输出打印到用户界面的相关简单要求,我认为这很复杂!

我现在从UI叫我的功能如下 -

 private void btInsertBCModls_Click(object sender, EventArgs e) 
     { 

      BackgroundWorker bw = new BackgroundWorker(); 
      bw.DoWork += RC2___Scratchpad4.BC_RunExistingBCModel; 

      bw.RunWorkerAsync(this); 

     } 

接下来,我用任何RichTextBox的委托& Invoke方法,我需要从另一个线程更新 -

delegate void UpdateWriteboxCallback(String str); 

    public void wbWriteBox(string WriteString) 
    { 
     if (!String.IsNullOrEmpty(WriteString)) 
     { 
      if (rtbWatchbox.InvokeRequired) 
      { 
       UpdateWriteboxCallback at = new UpdateWriteboxCallback(wbWriteBox); 
       this.Invoke(at, new object[] { WriteString }); 
      } 
      else 
      { 
       // append richtextbox as required 
      } 
     } 
    } 

然后从在我的功能我使用另一个BackgroundWorker来运行控制台的东西 -

public static void BC_RunExistingBCModel(object sender, DoWorkEventArgs e) 
    { 
      RC2___RhinegoldCoreForm frmC = e.Argument as RC2___RhinegoldCoreForm; 


      BackgroundWorker watchboxWorker = new BackgroundWorker(); 
      watchboxWorker.DoWork += frmC.WatchboxWorker_RunProc; 

      watchboxWorker.RunWorkerAsync(batLoc); 

      while (watchboxWorker.IsBusy) 
       Thread.Sleep(50); 

      frmC.UpdateRGCoreStatusBox4("Executed script " + m + "... "); 

    } 

而DoWork函数又调用上面的wbWriteBox函数。

public void WatchboxWorker_RunProc(object sender, DoWorkEventArgs e) 
    { 
     string exeLoc = (string) e.Argument; 

     string arg1 = exeLoc; 
     string arg2 = ""; 

     ProcessStartInfo pStartInfo = new ProcessStartInfo(); 

     pStartInfo.FileName = exeLoc; 
     pStartInfo.Arguments = string.Format("\"{0}\" \"{1}\"", arg1, arg2); 

     pStartInfo.WorkingDirectory = Path.GetDirectoryName(exeLoc); 
     pStartInfo.CreateNoWindow = true; 
     pStartInfo.UseShellExecute = false; 

     pStartInfo.RedirectStandardInput = true; 
     pStartInfo.RedirectStandardOutput = true; 
     pStartInfo.RedirectStandardError = true; 

     Process process1 = new Process(); 

     process1.EnableRaisingEvents = true; 

     process1.OutputDataReceived += (s, e1) => this.wbWriteBox(e1.Data); 
     process1.ErrorDataReceived += (s, e1) => this.wbWriteBox(e1.Data); 

     process1.StartInfo = pStartInfo; 
     process1.SynchronizingObject = rtbWatchbox; 

     process1.Start(); 
     process1.BeginOutputReadLine(); 
     process1.BeginErrorReadLine(); 

     process1.StandardInput.Close(); 

     process1.WaitForExit(); 

     //wbResetEvent.Set(); 

    } 

唷!一个棘手的解决方案,一个容易定义的问题。如果有人有更好的办法,让我知道。 感谢Carsten的所有帮助 - 宏伟。

相关问题