重定向Console输出到文本框
很多时候,我们需要捕获Console输出,然后在文本框等控件中显示。
例如SnippetCompiler就实现了编译源代码并将结果在下面的ListView显示的功能。
Console.SetOut(TextWriter)设置Console输出重定向,这样我们需要写一个TextWriter的派生类,这个类的构造函数我们传入要定向目标控件的引用,然后在 public override void Write(char value) 中修改引用控件的BeginInvoke方法挂一个Delegate关联控制台输出流到控件。代码如下,足够精简了。
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
{
get{ return 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将一直阻塞直到启动进程结束或者输出流关闭才能读到数据。
{
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.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);
}
}
}