在BackgroundWorker中运行进程

时间:2010-11-06 18:55:31

标签: c#

我对C#知之甚少。

我正在尝试使用后台命令行程序的状态显示进度条。

在c#中使用进度条和运行进程的google示例之后,我正在尝试在Windows窗体中启动BackgroundWorker,并在BackgroundWorker中运行命令行程序。我想解析命令行的输出以获得进度 百分比并将其显示在进度条中。

命令行程序是一个控制台程序,它会定期输出当前的进度状态。

但它似乎没有用。我无法读取流程标准输出的任何行。

我错过了什么吗?

以下是原始代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Diagnostics;
using System.IO;


public class DemoForm : Form
{
    private BackgroundWorker backgroundWorker1;
    private Button loadButton;
    private ProgressBar progressBar1;

    public DemoForm()
    {
        InitializeComponent();

        backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
        backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(
                this.backgroundWorker1_DoWork);
        backgroundWorker1.RunWorkerCompleted += 
            new System.ComponentModel.RunWorkerCompletedEventHandler(
                    this.backgroundWorker1_RunWorkerCompleted);
        backgroundWorker1.ProgressChanged += 
            new System.ComponentModel.ProgressChangedEventHandler(
                    this.backgroundWorker1_ProgressChanged);

    }

    private void loadButton_Click(object sender, EventArgs e)
    {
        backgroundWorker1.RunWorkerAsync();

        this.loadButton.Enabled = false;
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        string status;
        Process p = new Process();
        p.StartInfo.FileName = "xx.exe";
        p.StartInfo.Arguments = "-q -r test.cap -p";
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.CreateNoWindow = true;
        p.OutputDataReceived += this.p_OutputDataReceived;
        p.EnableRaisingEvents = true;
        p.Start();
        p.BeginOutputReadLine();

/*
        while((status = p.StandardOutput.ReadLine()) != null)
        {
            Console.WriteLine(status);
            string[] words = status.Split(' ');
            int offset = Convert.ToInt32(words[0]);
            int size   = Convert.ToInt32(words[1]);

            int percentComplete = 100 * offset / size;
            MessageBox.Show(words[0], words[1]);
            backgroundWorker1.ReportProgress(percentComplete);
        }
        Console.WriteLine("wait for exit!");
        StreamReader myStreamReader = p.StandardOutput;
        status = myStreamReader.ReadLine();
        Console.WriteLine(status);
        Console.WriteLine("wait for exit!");
        */
        p.WaitForExit();
    }

    void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        string status = e.Data;
        Console.WriteLine("get events");
        Console.WriteLine(status);
        string[] words = status.Split(' ');
        int offset = Convert.ToInt32(words[0]);
        int size   = Convert.ToInt32(words[1]);

        int percentComplete = 100 * offset / size;
        MessageBox.Show(words[0], words[1]);
        backgroundWorker1.ReportProgress(percentComplete);
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender,
            RunWorkerCompletedEventArgs e)
    {
        progressBar1.Value = 100;
        if (e.Error == null) {
            MessageBox.Show ("Demo", "Loading completed");
        }
    }

    private void backgroundWorker1_ProgressChanged(object sender,
            ProgressChangedEventArgs e)
    {
        this.progressBar1.Value = e.ProgressPercentage;
    }

    private System.ComponentModel.IContainer components = null;

    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
        this.loadButton = new System.Windows.Forms.Button();
        this.progressBar1 = new System.Windows.Forms.ProgressBar();

        /* load button */
        this.loadButton.Location = new System.Drawing.Point(12, 12);
        this.loadButton.Name = "loadButton";
        this.loadButton.Size = new System.Drawing.Size(100, 23);
        this.loadButton.TabIndex = 0;
        this.loadButton.Text = "Load file";
        this.loadButton.UseVisualStyleBackColor = true;
        this.loadButton.Click += new System.EventHandler(this.loadButton_Click);

        /* progress bar */
        this.progressBar1.Location = new System.Drawing.Point(12, 50);
        this.progressBar1.Name = "progressBar1";
        this.progressBar1.Size = new System.Drawing.Size(100, 26);
        this.progressBar1.TabIndex = 1;

        /* Form */
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.ClientSize = new System.Drawing.Size(133, 104);
        this.Controls.Add(this.progressBar1);
        this.Controls.Add(this.loadButton);
        this.Name = "DemoForm";
        this.Text = "DemoForm";
        this.ResumeLayout (false);
    }
}

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new DemoForm());
    }
}

或者有没有更好的方法来获得命令行程序的进展?

3 个答案:

答案 0 :(得分:2)

您必须将backgroundWorker的WorkerReportsProgress属性设置为true才能在backgroundWorker运行时进行报告:

backgroundWorker1.WorkerReportsProgress = true;

答案 1 :(得分:1)

手动刷新命令行程序的输出后,问题解决了。

fflush(stdout);

目前尚不清楚为什么即使一条线已经结束也会缓冲。

答案 2 :(得分:1)

在Kamyar所说的基础上,您需要编写一个委托来使用UserState对象捕获backgroundWorker对象的进度。这可能是任何对象,但您可以使用它来更新GUI的其他方面,在这种情况下是状态标签......

this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new   System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);

private class Progress
{
   public string Status { get; set; }
   public Progress(string status)
   {
      Status = status;
   }
}

//...

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
   while(myWork)
   {
      if(backgroundWorker1.CancellationPending)
      {
         e.Cancel = true;
         break;
      }

      int p = //...percentage calc
      backgroundWorker1.ReportProgress(p, new Progress("My message...")));
   }

   e.Cancel = false;
}

void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
        Progress p = (Progress)e.UserState;
        lStatus.Text = p.Status;
        progressBar.Value = e.ProgressPercentage;
}

这只是实现它的一种方法。

感谢。