如何在textBox中显示进程StandardOutput?

时间:2015-12-20 12:57:41

标签: c# .net winforms

在form1构造函数

cmd = " -i \"" + InputFile + "\" \"" + OutputFile + "\"";
backgroundWorker1.RunWorkerAsync();

然后

private void ConvertNow(string cmd)
        {

            System.Diagnostics.Process proc = new System.Diagnostics.Process();
            proc.StartInfo.FileName = exepath;
            proc.StartInfo.Arguments = cmd;
            proc.StartInfo.UseShellExecute = false;
            proc.StartInfo.CreateNoWindow = true;
            proc.StartInfo.RedirectStandardOutput = true;
            proc.Start();
            while (!proc.StandardOutput.EndOfStream)
            {
                string line = proc.StandardOutput.ReadLine();
                textBox1.Text = line;
            }
        }

然后在dowork事件中

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            ConvertNow(cmd);
        }

问题在于行中的ConvertNow方法:

while (!proc.StandardOutput.EndOfStream)

我使用了一个断点并且它已经开始了,但是程序在此行之后挂起它从不进入字符串和textBox行。

我怎样才能使它可以在textBox中替换输出,或者可能在更好的控件中创建richTextBox或者其他东西?

这就是我现在尝试的:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Diagnostics;

namespace ConvertVideo
{
    public partial class Form1 : Form
    {
        string InputFile = @"e:\lightningsmov\MVI_7909.MOV";
        string OutputFile = @"e:\lightningsmov\MVI_7909.mp4";
        string cmd;
        string exepath = @"E:\myffmpegstatic\ffmpeg-20151217-git-9d1fb9e-win64-static\bin\ffmpeg.exe";
        FileInfo fi;

        public Form1()
        {
            InitializeComponent();

            backgroundWorker1.WorkerReportsProgress = true;
            backgroundWorker1.ProgressChanged += (sender, e) => textBox1.AppendText((string)e.UserState);
            fi = new FileInfo(InputFile);
            label2.Text = InputFile;
            cmd = " -i \"" + InputFile + "\" \"" + OutputFile + "\"";
            backgroundWorker1.RunWorkerAsync();
        }

        private void ConvertNow(string cmd)
        {
            try
            {
                System.Diagnostics.Process proc = new System.Diagnostics.Process();
                proc.StartInfo.FileName = exepath;
                proc.StartInfo.Arguments = cmd;
                proc.StartInfo.UseShellExecute = false;
                proc.StartInfo.CreateNoWindow = true;
                proc.StartInfo.RedirectStandardOutput = true;

                // use this event
                proc.OutputDataReceived += (sender, e) => backgroundWorker1.ReportProgress(0, e.Data); // use this for synchronization

                proc.Start();

                // and start asynchronous read
                proc.BeginOutputReadLine();

                // wait until it's finished in your background worker thread
                proc.WaitForExit();
            }
            catch(Exception err)
            {
                string myerr = err.ToString();
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            ConvertNow(cmd);
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            textBox1.Text = e.ProgressPercentage.ToString();
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {

        }
    }
}

当我在线上使用断点时:

proc.OutputDataReceived += (sender, e) => backgroundWorker1.ReportProgress(0, e.Data);

然后把我的鼠标放在proc上,我看到所有属性都有相同的例外:

BasePriority =' proc.BasePriority'抛出类型' System.InvalidOperationException'

的例外

几乎所有的属性都是这样的。 试图添加尝试和捕捉,但它没有赶上捕获。

1 个答案:

答案 0 :(得分:0)

您的代码中存在一些问题。最糟糕的是:您尝试从与UI线程不同的线程更新控件。

我建议您将ConvertNow方法更改为以下内容:

private void ConvertNow(string cmd)
{
    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    proc.StartInfo.FileName = exepath;
    proc.StartInfo.Arguments = cmd;
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.CreateNoWindow = true;
    proc.StartInfo.RedirectStandardOutput = true;

    // use this event
    proc.OutputDataReceived += (sender, e) => backgroundWorker1.ReportProgress(0, e.Data); // use this for synchronization

    proc.Start();

    // and start asynchronous read
    proc.BeginOutputReadLine();

    // wait until it's finished in your background worker thread
    proc.WaitForExit();
}

向您的后台工作人员添加ProgressChanged事件(例如,在表单构造函数中):

backgroundWorker1.WorkerReportsProgress = true;
backgroundWorker1.ProgressChanged += (sender, e) => textBox1.AppendText((string)e.UserState);

现在,只要您的进程写入stdout,就会获得在UI线程上调用的事件,并将数据附加到文本框中。

更新:如果您已经拥有backgroundWorker1.ProgressChanged的处理程序,则无需添加其他处理程序,但可以直接在处理程序中插入行textBox1.AppendText((string)e.UserState);。但是如果你从我的其他部分调用backgroundWorker1.ReportProgress,你应该首先检查e.UserState是否实际上是一个应该添加到textBox的字符串。