在我的下面的代码中,我使用Process对象来执行一系列DOS批处理文件。 我正在缩短脚本列表,例如。
后续(1+)脚本通过事件处理程序(而不是for循环)执行。这样,每个后续脚本仅在前一个脚本完成时运行。现在出于某种原因,当我执行第二个脚本时,我无法通过错误消息填充状态栏来获取捕获的异常。
我正在测试在app-config文件中输入无效的脚本名称时,我怀疑我错误地使用了委托。我的匿名委托包含“新代码”和现有类方法的组合。那是我认为是错的;如果你们都能把我推向一个为什么我会欣赏它;)
注意:this.copy_scripts []是从Split of:“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();
}
答案 0 :(得分:1)
我认为不是使用事件来设置和继续循环,而是使用回调方法创建一个异步委托。完成此过程后,您只需再次回拨RunCopyScript(...)
即可。看看delegates on MSDN, and asynchronous programming。我确信有人可以通过Action
来做到这一点,我只是不太了解它给你一个例子。
我还看到了一个关于如何从交叉线程函数将输出转换为gui控件元素的简洁片段。 不幸的是,我找不到我之前看到的优雅编码...如果我碰到它,我会发布一个链接。
好的,这就是我所拥有的 - 它的价值。我相信它相当准确。我不希望它会开箱即用,因为我没有所有的文件,路径等来正确启动进程。将模拟批处理文件设置为Start()
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委托有更多优雅的实现,我相信它们可以是异步的。我希望有人提供一个例子。