C#在进程正常时显示文本框中子进程的标准输出

时间:2015-09-25 21:44:07

标签: c# child-process redirectstandardoutput

我有一个带有textBox output_txtB 的表单,我想运行cmd,执行一些命令并在文本框中显示标准输出。我想在执行每个命令后检索标准输出,而子进程正在工作。我在这里找到了一些解决方案:

Redirect the output (stdout, stderr) of a child process to the Output window in Visual Studio

C# get process output while running

但它没有解决我的具体问题,因为我想在文本框中显示标准输出(不在控制台或其他地方),并在执行每个命令后立即执行 - 我不想在之后检索完整输出流程退出。

我试图在子进程中使用OutputDataReceived事件,如上面的链接所示,但是有一个问题,当我想引用在另一个线程上创建的文本框时 - 它会抛出一个InvalidOperationException。 这是我的代码:

        Process process = new Process();
        process.EnableRaisingEvents = true;

        process.StartInfo.FileName = "cmd";
        process.StartInfo.CreateNoWindow = true;
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardInput = true;
        process.OutputDataReceived += (sender, args) =>
            {
                //here throws an exception
                output_txtB.AppendText(args.Data + Environment.NewLine);
            };

        process.Start();
        process.BeginOutputReadLine();

        //commands I want to execute
        process.StandardInput.WriteLine("example.exe");
        process.StandardInput.WriteLine("script.bat");
        process.StandardInput.WriteLine("ipconfig /all");
        process.StandardInput.WriteLine("dir");
        process.StandardInput.Close();

        process.WaitForExit();

例外的其他信息是:

跨线程操作无效:控制'output_txtB'从其创建的线程以外的线程访问。

任何想法,如何检索子进程的标准输出,并在子进程工作时将其显示在文本框中?

编辑: 请参阅“example.exe”代码:

        Console.WriteLine("line 1");
        System.Threading.Thread.Sleep(2000);
        Console.WriteLine("line 2");
        System.Threading.Thread.Sleep(2000);
        Console.WriteLine("line 3");
        System.Threading.Thread.Sleep(2000);
        Console.WriteLine("line 4");
        System.Threading.Thread.Sleep(2000);
        Console.WriteLine("line 5");

我想要实现的目标是每次在文本框 行X 中显示,该过程在标准输出中接收它。但即使我使用Stefano的解决方案,似乎OutputDataReceived事件会在进程退出后触发并显示完整的进程输出。

2 个答案:

答案 0 :(得分:1)

在UI线程外部对UI对象进行操作时,这是Windows窗体和WPF中的常见错误。

将Process.OutputDataReceived更改为:

process.OutputDataReceived += (s, args) =>
{
    this.output_txtB.BeginInvoke((MethodInvoker)delegate() { this.output_txtB.AppendText(args.Data + Environment.NewLine); });
};

答案 1 :(得分:1)

你应该使用Invoke()。

在其他主题中,您无法更新自己的观看次数。修改视图的逻辑应该在UI线程上完成,而Invoke()仅用于此。

很可能你在后台运行一个线程并从进程中读取输出。在此线程中,如果要更新UI,请使用Control.Invoke()方法,如下所示。

我更喜欢这种语法,因为" natural"它是:

    myControl.Invoke((Action)delegate
    {
        //You can put your UI update logic here
        myControl.Text = "Hello World from a different thread";
    });

此外,您不需要直接在正在修改的控件上调用Invoke。在任何控件中(或直接在您的表单上)调用invoke将意味着其中的代码将在UI线程上运行,这意味着您也可以更新其他UI。

    myControl.Invoke((Action)delegate
    {
        //You can put your UI update logic here
        myControl.Text = "Hello World from a different thread";
        myOtherControl.Text = "Look I can update other controls";
    });

    myForm.Invoke((Action)delegate
    {
        myControl.Text = "Can even call invoke from my Form";
    }