2010-02-11 43 views
0

在我的代码中,我使用Process对象来执行一系列DOS批处理文件。 例如,我缩短了脚本列表。可以调用执行引发异常的主UI线程代码吗?

后续(1+)脚本通过事件处理程序(而不是for循环)执行。这样,每个后续脚本只有在前一个脚本完成时才运行。现在由于某种原因,当我执行第二个脚本时,我无法获取捕获到的异常,以便用错误消息填充状态栏。

我正在测试什么时候在应用程序配置文件中输入了无效的脚本名称,而我嫌疑人我错误地使用了委托。我的匿名委托包含“新代码”和现有类方法的组合。那是什么认为是错的;如果你们都能推我朝着为什么我会感激;)

注:this.copy_scripts []是从拆分constructued: “goodname.bat,nosuchscript.bat”

private void copybutton_Click(object sender, EventArgs e) 
    { 

     InitializeBar(); 

     this.nbr_of_copy_exits_ = 0; 
     this.RunCopyScript(this.nbr_of_copy_exits_); 
     return; 
    } 

private void RunCopyScript(Int32 CopyScriptIdx) 
    { 
     Process proc = null; 
     try 
     { 
      proc = this.ObtainProcess(this.client_dest_dir_ + this.copy_scripts_[CopyScriptIdx]); 
      proc.EnableRaisingEvents = true; 
      proc.Exited += new EventHandler(CopyExited); 
      proc.Start(); 
      this.progressBar.Value = ProgressInPercent(this.copy_scripts_.Count(), CopyScriptIdx); 
     } 
     catch (Exception ex) 
     { 
      this.UpdateControl(this.toolStripStatusLabel1, "Error involving " + this.copy_scripts_[CopyScriptIdx] + ": " + ex.Message); 
      this.copybutton.BackColor = Color.Red; 
     } 
     return; 
    } 

void CopyExited(object sender, EventArgs e) 
    { 
     System.Diagnostics.Process senderProcess 
      = sender as System.Diagnostics.Process; 

     this.Invoke((MethodInvoker)delegate 
     { 
      if (++this.nbr_of_copy_exits_ == this.copy_scripts_.Count()) 
      { 
       this.UpdateControl(this.toolStripStatusLabel1, "Copying COMPLETE."); 
       this.progressBar.Value = 0; 
      } 
      else 
      { 
       this.RunCopyScript(this.nbr_of_copy_exits_); 
      } 
     }); 
    } 

     private void UpdateControl(ToolStripStatusLabel tssl, String text) 
    { 
     tssl.Text = text; 
     tssl.Refresh(); 
    } 

回答

1

我认为,而不是使用事件来设置和继续循环,我会创建一个带有回调方法的异步委托。过程完成后,您只需再次拨打RunCopyScript(...)即可。看看delegates on MSDN, and asynchronous programming。我相信有人会用Action这样做,我只是不太清楚它给你一个例子。

我还看到了一个关于如何从一个交叉线程函数中将输出转化为gui控制元素的整洁代码片段。 不幸的是,我找不到前面看到的优雅编码...如果我碰到它,我会发布一个链接到它

好的,这是我的 - 这是值得的。我相信这是相当准确的。我不希望它能够立即编译,因为我没有所有文件,路径等来正确启动进程。并设置模拟批处理文件到Start() a Process将需要相当多的工作。我希望你应该能够处理这个问题,如果与我上面提供的链接交叉引用,你可以更接近你想要的东西。

我还评论了一些不需要的代码,我移动了,或者没有被识别。另外,我没有对你目前的try/catch区块做任何事情。

// same signature as the method to be called asynchronously 
delegate void RunScript(Int32 scriptIdx); 

// declare IAsyncResult 
IAsyncResult result; 

Process proc = null; 

private void copybutton_Click(object sender , EventArgs e) 
{ 
    InitializeBar(); 

    nbr_of_copy_exits_ = 0; 
    //this.RunCopyScript(this.nbr_of_copy_exits_); 
    RunScript start = new RunScript(RunCopyScript); 

    result = start.BeginInvoke(nbr_of_copy_exits_ , new AsyncCallback(CopyExited) , proc); 
    copybutton.Enabled = false // you don't want the button to be clicked again. 
} 

private void RunCopyScript(Int32 CopyScriptIdx) 
{ 
    try 
    { 
     proc = ObtainProcess(client_dest_dir_ + copy_scripts_[CopyScriptIdx]); 
     proc.EnableRaisingEvents = true; 
     //proc.Exited += new EventHandler(CopyExited); 
     proc.Start(); 
     progressBar.Value = ProgressInPercent(copy_scripts_.Count() , CopyScriptIdx); 
    } 
    catch (Exception ex) 
    { 
     UpdateControl(this.toolStripStatusLabel1, "Error involving " + copy_scripts_[CopyScriptIdx] + ": " + 
      ex.Message); 
     copybutton.BackColor = Color.Red; 
    } 
    //return; 
} 

void CopyExited(IAsyncResult iaRes) 
{ 
    AsyncResult result = (AsyncResult)iaRes; 
    RunScript caller = (RunScript)result.AsyncDelegate; 

    Process senderProcess = (Process)iaRes.AsyncState; 
    caller.EndInvoke(iaRes); 

    if (++this.nbr_of_copy_exits_ == this.copy_scripts_.Count()) 
    { 
     UpdateControl(toolStripStatusLabel1 , "Copying COMPLETE."); 
     copybutton.Enabled = true; // enable the button now that we're done 
    } 
    else 
    { 
     // start the process all over again 
     iaRes = caller.BeginInvoke(this.nbr_of_copy_exits_ , new AsyncCallback(CopyExited) , proc); 
    } 
} 

private void UpdateControl(ToolStripStatusLabel tssl , String text) 
{ 
    Invoke((MethodInvoker)delegate 
    { 
     tssl.Text = text; 
     progressBar.Value = 0; 
    }); 

    //tssl.Refresh(); 'System.Windows.Forms.ToolStripStatusLabel' does not contain a definition for 'Refresh'... 
} 

正如我所说的,有更多优雅的使用Action委托的实现,我确信它们可以是异步的。我希望有人提供一个例子。

+0

很好,谢谢你的工作。我尝试了你的方法,不幸的是得到了相同的结果。但是你的方法使用了我还没有的东西:Begin/EndInvoke,委托定义,IAsync等,我很快就会使用它们。谢谢。 – Joe 2010-02-17 00:40:13

+0

@Joe:我不确定我能接近多远来帮助你,但我认为这可能值得努力尝试。 – IAbstract 2010-02-17 02:06:25

+0

绝对是。我会交换一个仍然没有解决的小问题(即:应用程序配置文件不可能被更改为开始,更不用说其中有无效条目),以便随时采用新的方式。这是我绝对会使用的很好的信息。我们'自嘲'需要坚持到一起。这并不容易,有它;) – Joe 2010-02-17 21:35:23

相关问题