【问题标题】:Problem with System.Diagnostics.Process RedirectStandardOutput to appear in Winforms Textbox in real-timeSystem.Diagnostics.Process RedirectStandardOutput 问题实时出现在 Winforms 文本框中
【发布时间】:2023-03-18 18:25:01
【问题描述】:

我遇到了来自控制台应用程序的重定向输出实时显示在 Winforms 文本框中的问题。消息正在逐行生成,但是一旦需要与表单进行交互,似乎什么都没有显示。

根据 Stackoverflow 和其他论坛上的许多示例,在流程完成之前,我似乎无法将流程的重定向输出显示在表单的文本框中。

通过将调试行添加到“stringWriter_StringWritten”方法并将重定向的消息写入调试窗口,我可以看到在进程运行期间到达的消息,但这些消息在进程完成之前不会出现在表单的文本框中。

感谢您对此提出的任何建议。

这是代码的摘录

public partial class RunExternalProcess : Form
{
    private static int numberOutputLines = 0;
    private static MyStringWriter stringWriter;

    public RunExternalProcess()
    {
        InitializeComponent();

        // Create the output message writter
        RunExternalProcess.stringWriter = new MyStringWriter();
        stringWriter.StringWritten += new EventHandler(stringWriter_StringWritten);

        System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();

        startInfo.FileName = "myCommandLineApp.exe";

        startInfo.UseShellExecute = false;
        startInfo.RedirectStandardOutput = true;
        startInfo.CreateNoWindow = true;
        startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;

        using (var pProcess = new System.Diagnostics.Process())
        {
            pProcess.StartInfo = startInfo;
            pProcess.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(RunExternalProcess.Process_OutputDataReceived);
            pProcess.EnableRaisingEvents = true;

            try
            {
                pProcess.Start();

                pProcess.BeginOutputReadLine();
                pProcess.BeginErrorReadLine();

                pProcess.WaitForExit();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            finally
            {
                pProcess.OutputDataReceived -= new System.Diagnostics.DataReceivedEventHandler(RunExternalProcess.Process_OutputDataReceived);
            }
        }
    }

    private static void Process_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
    {
        if (!string.IsNullOrEmpty(e.Data))
        {
            RunExternalProcess.OutputMessage(e.Data);
        }
    }

    private static void OutputMessage(string message)
    {
        RunExternalProcess.stringWriter.WriteLine("[" + RunExternalProcess.numberOutputLines++.ToString() + "] - " + message);
    }

    private void stringWriter_StringWritten(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.WriteLine(((MyStringWriter)sender).GetStringBuilder().ToString());

        SetProgressTextBox(((MyStringWriter)sender).GetStringBuilder().ToString());
    }

    private delegate void SetProgressTextBoxCallback(string text);

    private void SetProgressTextBox(string text)
    {
        if (this.ProgressTextBox.InvokeRequired)
        {
            SetProgressTextBoxCallback callback = new SetProgressTextBoxCallback(SetProgressTextBox);
            this.BeginInvoke(callback, new object[] { text });
        }
        else
        {
            this.ProgressTextBox.Text = text;
            this.ProgressTextBox.Select(this.ProgressTextBox.Text.Length, 0);
            this.ProgressTextBox.ScrollToCaret();
        }
    }
}

public class MyStringWriter : System.IO.StringWriter
{
    // Define the event.
    public event EventHandler StringWritten;

    public MyStringWriter()
        : base()
    {
    }

    public MyStringWriter(StringBuilder sb)
        : base(sb)
    {
    }

    public MyStringWriter(StringBuilder sb, IFormatProvider formatProvider)
        : base(sb, formatProvider)
    {
    }

    public MyStringWriter(IFormatProvider formatProvider)
        : base(formatProvider)
    {
    }

    protected virtual void OnStringWritten()
    {
        if (StringWritten != null)
        {
            StringWritten(this, EventArgs.Empty);
        }
    }

    public override void Write(char value)
    {
        base.Write(value);
        this.OnStringWritten();
    }

    public override void Write(char[] buffer, int index, int count)
    {
        base.Write(buffer, index, count);
        this.OnStringWritten();
    }

    public override void Write(string value)
    {
        base.Write(value);
        this.OnStringWritten();
    }
}

【问题讨论】:

    标签: c# winforms redirect process console


    【解决方案1】:
       pProcess.WaitForExit();
    

    您正在挂起 UI 线程。在进程退出之前,它不会执行其正常职责,例如绘制文本框。同样,在 UI 线程再次空闲之前,BeginInvoke() 委托目标无法运行。它们会堆积在调用队列中,在极端情况下你会耗尽内存。即使在进程退出后,UI 线程在清空队列时也会有一段时间没有响应。

    你在这里不需要它。如有必要,请改用 Process.Exited 事件。

    【讨论】:

    • 非常感谢就是这样。不幸的是,当进程退出时,Exited 事件处理程序没有触发,因此需要进行更多调试。
    • 也知道了,这取决于“使用”语句,所以我的进程正在被清理,因此退出事件没有被触发,因为 WaitForExit() 调用不在“使用'块。
    猜你喜欢
    • 2011-05-02
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2013-08-28
    • 1970-01-01
    • 2011-09-26
    • 2017-09-05
    相关资源
    最近更新 更多