代码之家  ›  专栏  ›  技术社区  ›  Sam Liao

在BackgroundWorker中运行进程

c#
  •  0
  • Sam Liao  · 技术社区  · 14 年前

    我对C#知之甚少。

    在google的progressbar和run process示例之后,我试图在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 回复  |  直到 14 年前
        1
  •  2
  •   Kamyar    14 年前

    你必须设置 WorkerReportsProgress

    backgroundWorker1.WorkerReportsProgress = true;
    
        2
  •  1
  •   Sam Liao    14 年前

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

    fflush(stdout);
    

        3
  •  1
  •   Morbo    11 年前

    基于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;
    }
    

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

    谢谢。