重定向Console输出到文本框

很多时候,我们需要捕获Console输出,然后在文本框等控件中显示。
例如SnippetCompiler就实现了编译源代码并将结果在下面的ListView显示的功能。
Console.SetOut(TextWriter)设置Console输出重定向,这样我们需要写一个TextWriter的派生类,这个类的构造函数我们传入要定向目标控件的引用,然后在 public override void Write(char value) 中修改引用控件的BeginInvoke方法挂一个Delegate关联控制台输出流到控件。代码如下,足够精简了。

using System;
using System.Windows.Forms;

namespace Console2TextBox
{
        public class TextBoxWriter : System.IO.TextWriter
        {
            TextBox txtBox;
            delegate void VoidAction();
            
            public TextBoxWriter(TextBox box)
            {
                txtBox = box; //transfer the enternal TextBox in
            }
            
            public override void Write(char value)
            {
                //base.Write(value);//still output to Console
                VoidAction action = delegate{
                    txtBox.AppendText(value.ToString());
                };
                txtBox.BeginInvoke(action);
            }
            
            public override System.Text.Encoding Encoding
            {
                getreturn System.Text.Encoding.UTF8;}
            }
        }    
        
        public class Program
        {
            public static void Main()
            {
                //TextBox, receive the output from Console
                TextBox txtOutput = new TextBox{Multiline = true};
                txtOutput.Dock = System.Windows.Forms.DockStyle.Fill;
                //Timer output current time to Console
                var timer = new Timer{ Enabled = true, Interval = 1000};
                timer.Tick += delegate{
                    System.Console.WriteLine(DateTime.Now.TimeOfDay.ToString());
                };
                //redirect console output to textbox
                Console.SetOut(new TextBoxWriter(txtOutput));
                //Form
                Form form = new Form();
                form.Controls.Add(txtOutput);
                Application.Run(form);
            }
    }
    
}

以上是将当前Console.SetOut重定向到当前Windows.Forms.Controls,如果用Process.Start启动的另外的进程,就不是那么回事了。
首先,同步方式:首先 StandardInput.WriteLine(strCmd) 向标准输入提供消息,然后用 StandardOutput.ReadToEnd();读取消息;
但可能ReadToEnd将一直阻塞直到启动进程结束或者输出流关闭才能读到数据。

    public static void Main()
    {
        var startInfo = new System.Diagnostics.ProcessStartInfo{
            FileName="cmd.exe"
            UseShellExecute =  false,  // 是否使用外壳程序
            RedirectStandardInput =  true,  // 重定向输入流
            RedirectStandardOutput= true,  //重定向输出流
            RedirectStandardError= true,  //重定向错误流
            CreateNoWindow = true   //是否在新窗口中启动该进程的值 
        };        
        System.Diagnostics.Process cmd =  new System.Diagnostics.Process();
        cmd.StartInfo = startInfo;

        string strCmd =  "ping www.baidu.com \r\n";
        strCmd += "exit\r\n";//cmd只有关闭后才关闭输出流,否则ReadToEnd将一直等待    
        cmd.Start();
        cmd.StandardInput.WriteLine(strCmd);//向CMD输入ping命令和Exit命令
        
//获取输出信息 : 执行到ReadToEnd将一直阻塞直到cmd进程结束(输出流关闭)!!!
        string output = cmd.StandardOutput.ReadToEnd();
        System.Windows.Forms.MessageBox.Show(output);
    }

采用异步方式能更好的实现这一功能,下面演示 ping 命令的异步效果,你将看到数据是一行一行输出,而不是像上面等到ping命令退出后忽然输出所有数据.

using System;
using System.Diagnostics;
using System.Windows.Forms;

namespace Console2TextBox
{      public class FormConsoleRedirect : Form
        {
            TextBox txtOutput;
            public Process cmd;
            
            public FormConsoleRedirect()
            {
                //TextBox, receive the output from Console
                txtOutput = new TextBox{Multiline = true};
                txtOutput.Dock = System.Windows.Forms.DockStyle.Fill;
                 //redirect console output to textbox
                System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo{
                    FileName="cmd",
                    UseShellExecute=false,
                    CreateNoWindow=true,
                    RedirectStandardInput = true,
                    RedirectStandardError=true,
                    RedirectStandardOutput=true
                };
                cmd = new Process();
                int i=0;
                cmd.OutputDataReceived +=(s,e)=>{
                    string infoText = string.Format("{0,4 }:{1}\r\n",i++,e.Data);
                    txtOutput.AppendText(infoText); 
                };                
                cmd.ErrorDataReceived +=(s,e)=>{
                    string infoText = string.Format("{0,4 }:{1}\r\n",i++,e.Data);
                    txtOutput.AppendText(infoText); 
                };
                cmd.StartInfo = info;
                cmd.EnableRaisingEvents = true;
                cmd.Start();
                cmd.BeginOutputReadLine();
                cmd.BeginErrorReadLine();
                
                //form.Controls
                this.Controls.Add(txtOutput);
            }
            
            
        }
        public class Program
        {
            public static void Main()
            {
                //Form
                FormConsoleRedirect form = new FormConsoleRedirect();
                string strCmd =  "ping www.163.com \r\nExit\r\n";                
                form.cmd.StandardInput.WriteLine(strCmd);
                Application.Run(form);
            }
    }
    
}


 

原文地址:https://www.cnblogs.com/flaaash/p/3084841.html