如何将进程输出(控制台)重定向到richtextbox?

时间:2011-06-29 13:32:18

标签: c#

有什么问题,为什么richtextbox不能获得Process输出流?在richtextbox中没有文字显示..

 private void button1_Click(object sender, EventArgs e)
    {

        Process sortProcess;
        sortProcess = new Process();
        sortProcess.StartInfo.FileName = "sort.exe";
        sortProcess.StartInfo.Arguments = this.comboBox1.SelectedItem.ToString();
        // Set UseShellExecute to false for redirection.
        sortProcess.StartInfo.CreateNoWindow = true;
        sortProcess.StartInfo.UseShellExecute = false;



        // Redirect the standard output of the sort command.  
        // This stream is read asynchronously using an event handler.
        sortProcess.StartInfo.RedirectStandardOutput = true;
        sortOutput = new StringBuilder("");

        // Set our event handler to asynchronously read the sort output.
        sortProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);

        // Redirect standard input as well.  This stream
        // is used synchronously.
        sortProcess.StartInfo.RedirectStandardInput = true;

        // Start the process.
        sortProcess.Start();



        // Start the asynchronous read of the sort output stream.
        sortProcess.BeginOutputReadLine();
        sortProcess.WaitForExit();


        richTextBox1.AppendText(sortOutput.ToString());
    }

    private static void SortOutputHandler(object sendingProcess,
        DataReceivedEventArgs outLine)
    {
            sortOutput.Append(Environment.NewLine +
                "[" + numOutputLines.ToString() + "] - " + outLine.Data);
        }
    }

所以当sort.exe启动时,它显示文本,我希望所有这些文本也显示在RealTime的richtextbox中(我不想等待进程退出,然后读取所有输出)

我该怎么办?我的代码中有任何错误的部分?感谢

更新@botz

我在我的代码中添加了这个

 private void SortOutputHandler(object sendingProcess,
        DataReceivedEventArgs outLine)
    {

            sortOutput.Append(Environment.NewLine +
                "[" + numOutputLines.ToString() + "] - " + outLine.Data);
            richTextBox1.AppendText(sortOutput.ToString());


    }

但它会抛出此异常

Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on.

5 个答案:

答案 0 :(得分:5)

WaitForExit()会阻止您的UI线程,因此您看不到新的输出。 要么在单独的线程中等待进程,要么用这样的代码替换WaitForExit()

while (!sortProcess.HasExited) {
     Application.DoEvents(); // This keeps your form responsive by processing events
}

SortOutputHandler中,您现在可以直接将输出附加到文本框中。但是你应该记得检查是否需要在UI线程上调用它。

您可以在处理程序中以这种方式检查它是否在UI线程中:

    if (richTextBox1.InvokeRequired) { richTextBox1.BeginInvoke(new DataReceivedEventHandler(SortOutputHandler), new[] { sendingProcess, outLine }); }
    else {
        sortOutput.Append(Environment.NewLine + "[" + numOutputLines.ToString() + "] - " + outLine.Data);
        richTextBox1.AppendText(sortOutput.ToString());
    }

答案 1 :(得分:3)

这对我有用:

private void button1_Click(object sender, EventArgs e)
    {
        using (Process sortProcess = new Process())
        {
            sortProcess.StartInfo.FileName = @"F:\echo_hello.bat";
            sortProcess.StartInfo.CreateNoWindow = true;
            sortProcess.StartInfo.UseShellExecute = false;
            sortProcess.StartInfo.RedirectStandardOutput = true;

            // Set event handler
            sortProcess.OutputDataReceived += new DataReceivedEventHandler(SortOutputHandler);

            // Start the process.
            sortProcess.Start();

            // Start the asynchronous read
            sortProcess.BeginOutputReadLine();

            sortProcess.WaitForExit();
        }
    }

    void SortOutputHandler(object sender, DataReceivedEventArgs e)
    {
        Trace.WriteLine(e.Data);
        this.BeginInvoke(new MethodInvoker(() =>
        {
            richTextBox1.AppendText(e.Data ?? string.Empty);
        }));
    }

The example you started with是一个控制台应用程序,它不关心多线程访问。对于Windows窗体,当您更新控件时,必须从主UI线程完成,这就是需要BeginInvoke的原因。如果您想快速检查SortOutputHandler之类的处理程序是否正常工作,您可以使用System.Diagnostics.Trace.Write*,而不需要BeginInvoke

编辑: echo_hello.bat简单地回应“你好”字符串:

@echo off
echo hello

答案 2 :(得分:0)

如果你要从另一个线程更新ui,你需要确保你在主ui线程上。在方法中检查InvokeRequired。见InvokeRequired

答案 3 :(得分:0)

可从codeproject的外部链接获得完整的应用程序和源代码:

http://www.codeproject.com/Articles/335909/Embedding-a-Console-in-a-C-Application

这是https://github.com/dwmkerr/consolecontrol的实施教程。

答案 4 :(得分:0)

正如我在发布给问题的评论中所说,根据定义排序的含义,在读取所有输入之前不可能有任何输出。因此,排序程序是实时获取输出的不良示例。因此,以下内容适用于将来希望对控制台程序进行一般操作的任何人。以下使用BackgroundWorker异步获取输出并将其放入TextBox中。可以轻松地使用RichTextBox

public partial class MainWindow : Window
{
    const string Path = @"C:\Windows\system32\sort.exe";
    BackgroundWorker Processer = new BackgroundWorker();

    public MainWindow()
    {
        InitializeComponent();
        Processer.WorkerReportsProgress = true;
        Processer.WorkerSupportsCancellation = true;
        Processer.ProgressChanged += Processer_ProgressChanged;
        Processer.DoWork += Processer_DoWork;
    }

    private void Processer_DoWork(object sender, DoWorkEventArgs e)
    {
        StreamReader StandardOutput = e.Argument as StreamReader;
        string data = StandardOutput.ReadLine();
        while (data != null)
        {
            Processer.ReportProgress(0, data);
            data = StandardOutput.ReadLine();
        }
    }

    private void Processer_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        string data = e.UserState as string;
        if (data != null)
            DataBox.Text += data + "\r\n";
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        DataBox.Text = string.Empty;
        ProcessStartInfo StartInfo = new ProcessStartInfo(Path);
        StartInfo.RedirectStandardOutput = true;
        StartInfo.RedirectStandardInput = true;
        StartInfo.UseShellExecute = false;
        Process p = null;
        try { p = Process.Start(StartInfo); }
        catch (Exception ex)
        {
            MessageBox.Show($"Error starting {Path}: {ex.Message}");
            return;
        }
        // Get the output
        Processer.RunWorkerAsync(p.StandardOutput);
        // Put the input
        p.StandardInput.WriteLine("John");
        p.StandardInput.WriteLine("Alice");
        p.StandardInput.WriteLine("Zoe");
        p.StandardInput.WriteLine("Bob");
        p.StandardInput.WriteLine("Mary");
        // Tell the program that is the last of the data
        p.StandardInput.Close();
    }
}

对于排序程序,直到读取完所有数据之后才需要调用ReportProgress,但这是一个更通用的示例。