可以调用执行抛出异常的主UI线程代码吗?

时间:2010-02-11 17:12:22

标签: .net exception process delegates invoke

在我的下面的代码中,我使用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();
    }

1 个答案:

答案 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委托有更多优雅的实现,我相信它们可以是异步的。我希望有人提供一个例子。