使用 UI 应用程序交互式读取和写入命令行

Interactively reading from and writing to command line with UI application

我有 UI 应用程序使用不同的参数定期调用 cmd,我想使用 cmd 输出结果定期更新 UI。
这是我使用的代码,但问题是 UI 仅在执行所有命令时更新,而不是在执行每个命令后更新,而且我没有找到执行每个命令时定期更新 UI 的解决方案:

    ProcessStartInfo psi = new ProcessStartInfo()
    {
        FileName = "cmd.exe",
        WindowStyle = ProcessWindowStyle.Hidden,
        UseShellExecute = false,
        RedirectStandardInput = true,
        RedirectStandardOutput = true,
        CreateNoWindow = true,
    };
    Process p = new Process();
    p.StartInfo = psi;
    p.Start();

    var reposToUpdate = ConfigurationManager.AppSettings["UpdateAndMergeReposOnBranch"];
    foreach (XmlNode repoPathNode in reposPaths)
    {
        var repoPath = repoPathNode.Attributes["root"].Value;
        p.StandardInput.WriteLine(string.Format("cd {0}", repoPath));
        p.StandardInput.WriteLine(@"hg update --check");
        p.StandardInput.Flush();
    }

    p.StandardInput.Close();
    string output = p.StandardOutput.ReadToEnd();
    rtbOutput.Text = output;

您可以订阅 Process.OutputDataReceived 事件而不是使用 Process.StandardOutput.ReadToEnd 方法:

ProcessStartInfo psi = new ProcessStartInfo()
{
    FileName = "cmd.exe",
    WindowStyle = ProcessWindowStyle.Hidden,
    UseShellExecute = false,
    RedirectStandardInput = true,
    RedirectStandardOutput = true,
    CreateNoWindow = true,
};
Process p = new Process();
p.StartInfo = psi;
p.Start();

// Output handling:
p.OutputDataReceived += (o, e) => Console.WriteLine(e.Data);
p.BeginOutputReadLine();

var reposToUpdate = ConfigurationManager.AppSettings["UpdateAndMergeReposOnBranch"];
foreach (XmlNode repoPathNode in reposPaths)
{
    var repoPath = repoPathNode.Attributes["root"].Value;
    p.StandardInput.WriteLine(string.Format("cd {0}", repoPath));
    p.StandardInput.WriteLine(@"hg update --check");
    p.StandardInput.Flush();
}

p.StandardInput.Close();

在上面的例子中所有的数据打印到Console。或者,您可以将输出附加到文本框:

p.OutputDataReceived += (o, e) => rtbOutput.Invoke((MethodInvoker)(() => rtbOutput.Text += e.Data));

请注意,您还应该处理 Process.Exited 事件。

您正在寻找的是 BeginOutputReadLine 方法和相关事件,用于接收过程中发生的数据。

p.OutputDataReceived += OnOutputDataReceived;
p.BeginOutputReadLine ();
p.WaitForExit();

然后在别处添加一个方法

void OnOutputDataReceived (object sender, DataReceivedEventArgs e)
{
   // DO Something with the output
}        

还有一个 ErrorDataReceived 事件将挂接到 stderr