Проблема с System.Diagnostics.Process RedirectStandardOutput для отображения в текстовом поле Winforms в режиме реального времени - PullRequest
1 голос
/ 07 мая 2010

У меня проблемы с перенаправленным выводом из консольного приложения, которое отображается в текстовом поле Winforms в режиме реального времени. Сообщения выводятся построчно, однако, как только будет вызвано взаимодействие с формой, ничего не отобразится.

Следуя многочисленным примерам как на Stackoverflow, так и на других форумах, я не могу заставить перенаправленный вывод процесса отображаться в текстовом поле на форме, пока процесс не завершится.

Добавляя строки отладки в метод 'stringWriter_StringWritten' и записывая перенаправленные сообщения в окно отладки, я вижу сообщения, поступающие во время выполнения процесса, но эти сообщения не появятся в текстовом поле формы, пока процесс не завершится. 1005 *

Благодарен за любые советы по этому вопросу.

Вот выдержка из кода

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();
    }
}

1 Ответ

1 голос
/ 07 мая 2010
   pProcess.WaitForExit();

Вы вешаете поток пользовательского интерфейса с этим. Он не сможет выполнять свои обычные обязанности, например рисовать текстовое поле, пока процесс не завершится. Точно так же цель делегата BeginInvoke () не может работать до тех пор, пока поток пользовательского интерфейса не перейдет в режим ожидания. Они будут складываться в очередь вызовов, в крайних случаях вам не хватит памяти. Даже после завершения процесса поток пользовательского интерфейса будет не отвечать на запросы в течение некоторого времени, пока он работает при очистке очереди.

Тебе здесь не нужно. При необходимости используйте вместо этого событие Process.Exited.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...