UI冻结使用外部流程

时间:2012-04-12 15:47:52

标签: c# .net winforms

我已经实现了以下代码(改编自tutorial),以便运行命令提示符窗口,运行程序并读取输出。从ButtonClick事件处理程序调用代码,该处理程序嵌套在用户控件中。

我的印象是,由于这些方法是“异步的”,这将允许我的程序的其余部分在外部进程运行时运行。但是,这似乎并非如此,因为我的UI将在操作运行时冻结。我应该补充一点,当cmd进程结束时收到的输出是正确的。

很抱歉转储这样的代码,只是不确定此时还要做什么!

非常感谢任何协助。

public static void runExternalProcess()
{
    StringBuilder output = new StringBuilder();

    Process cmd = new Process();
    cmd.StartInfo.FileName = "cmd.exe";          
    cmd.StartInfo.UseShellExecute = false;
    cmd.StartInfo.CreateNoWindow = true;
    cmd.StartInfo.RedirectStandardOutput = true;

    cmd.OutputDataReceived += new DataReceivedEventHandler(outputEventHandler);        
    cmd.StartInfo.RedirectStandardInput = true;        
    cmd.Start();
    cmd.BeginOutputReadLine();      

    StreamWriter sortStreamWriter = cmd.StandardInput; 
    StreamWriter sw = cmd.StandardInput;

    if (sw.BaseStream.CanWrite)
    {
        sw.WriteLine("ping www.google.com");
    }

    sw.Close();

    cmd.WaitForExit();

    MessageBox.Show(output.ToString());

    cmd.Close();
}

private static void outputEventHandler(object sendingProcess, DataReceivedEventArgs e)
{
    if (!String.IsNullOrEmpty(e.Data))
    {
        output.Append(e.Data + Environment.NewLine);
    }
}

3 个答案:

答案 0 :(得分:4)

你的问题在这里:

cmd.WaitForExit();

这是阻止通话。

如果您想在不阻止的情况下响应退出流程,则需要为Exited事件添加处理程序。

答案 1 :(得分:4)

如何注册Exited事件并在那里显示MessageBox

StringBuilder output = new StringBuilder();
Process cmd = new Process();

public void RunExternalPing()
{
   cmd.StartInfo.FileName = "cmd.exe";
   cmd.StartInfo.UseShellExecute = false;
   cmd.StartInfo.CreateNoWindow = true;
   cmd.StartInfo.RedirectStandardOutput = true;
   cmd.StartInfo.RedirectStandardInput = true;

   cmd.EnableRaisingEvents = true;
   cmd.OutputDataReceived += 
      new DataReceivedEventHandler(cmd_OutputDataReceived);
   cmd.Exited += new EventHandler(cmd_Exited);

   cmd.Start();
   cmd.BeginOutputReadLine();
   StreamWriter sw = cmd.StandardInput;
   sw.WriteLine("ping www.google.com");
   sw.Close();
}

void cmd_Exited(object sender, EventArgs e)
{
   MessageBox.Show(output.ToString());
   cmd.Dispose();
}

private void cmd_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
   if (!String.IsNullOrEmpty(e.Data))
   {
      output.Append(e.Data + Environment.NewLine);
   }
}

来自MSDN:

  

关联过程有两种方式得到通知   退出:同步和异步。同步通知   依赖于调用WaitForExit方法来暂停处理   您的应用程序,直到相关组件退出。异步   通知依赖于退出事件。在任一情况下,   对于Process组件,必须将EnableRaisingEvents设置为true   收到流程已退出的通知。

答案 2 :(得分:2)

所有这些代码都是线性的,如果你不想冻结你所在的线程,你应该创建一个新线程并在该线程完成时执行回调。

查看BackgroundWorker