1

我正在尝试编写一个控制台包装 WPF gui,它只运行选择的 .bat 文件,我希望能够“实时”查看 .bat 文件的任何输出(就像它在 cmd 中运行一样)。

我查看了 OutputDataReceived 和事件处理程序,它们附加文本然后将其发送到屏幕,但是它仍然等到进程完成,然后屏幕上才会出现任何内容。

如何让 .bat 的输出“实时”显示?


到目前为止我的代码片段(这是一种形式):

该表单有一个按钮 ( go) 和一个多行文本字段 ( textArea)。

private void go_Click(object sender, EventArgs e)
{
    ExecuteCommand();
}

public void ExecuteCommand()
{

    int ExitCode;
    ProcessStartInfo ProcessInfo;
    Process Process;

    //ProcessInfo = new ProcessStartInfo("cmd.exe", "/C z:\foo.bat");
    ProcessInfo = new ProcessStartInfo(@"z:\foo.bat"); ;

    ProcessInfo.CreateNoWindow = true;
    ProcessInfo.UseShellExecute = false;

    ProcessInfo.RedirectStandardError = true;
    ProcessInfo.RedirectStandardOutput = true;

    Process = new Process();
    Process.StartInfo = ProcessInfo;

    Process.OutputDataReceived += new DataReceivedEventHandler(OutputToTextArea);

    Process.Start();

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

    Process.WaitForExit();

    ExitCode = Process.ExitCode;
    Process.Close();
}

private int numOutputLines = 0;
private void OutputToTextArea(object sendingProcess, DataReceivedEventArgs outLine)
{
    // Collect the sort command output. 
    if (!String.IsNullOrEmpty(outLine.Data))
    {
        numOutputLines++;

        this.AppendToTextArea("[" + numOutputLines.ToString() + "] - " + outLine.Data + Environment.NewLine);
    }
}

private void AppendToTextArea(string s)
{
    if (this.textArea.InvokeRequired)
    {
        // It's on a different thread, so use Invoke.
        this.BeginInvoke (new MethodInvoker(() => textArea.AppendText(s)));
    } else {
        textArea.AppendText(s);
    }
}

我的 foo.bat 只是一个 for 循环:

ECHO OFF

FOR /L %%i IN (1,1,10) DO (
   echo %%i
   ping -n 2 127.0.0.1 >nul
)
4

2 回答 2

4

是的,当您等待进程退出时,您当前正在阻塞主线程(即 UI 线程)ExecuteCommand,该进程直接从 UI 线程(在 中go_Click)调用。

只需启动一个新线程(或使用ThreadPool)(Winforms 示例):

private void button1_Click(object sender, EventArgs e)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(this.ExecuteCommand));
}

public void ExecuteCommand(object state)
{
    ...
}

如果您使用的是 WPF,您可能希望使用BackgroundWorker.

于 2013-01-29T12:56:12.480 回答
1

如果您希望保持简单,您可以使用 /K 参数启动命令提示符并传入批处理文件。

string arguments = @"z:\foo.bat";

Process.Start("cmd.exe", "/K " + arguments);

cmd.exe /K 打开命令提示符并运行您的 foo.bat 但仍保留在屏幕上。

于 2013-01-29T13:24:49.080 回答