geogeek
geogeek

Reputation: 1302

Process in background worker error

while the execution of a time consuming python script , i would manage the IU with background worker to display a progress bar.

i have used the background worker successfully when i needn't the event OutputDataReceived , but the script that i'm using prints some progress values like ("10" , "80",..), so i got to listen the event OutputDataReceived.

i get this error : This operation has already had OperationCompleted called on it and further calls are illegal. in this line progress.bw.ReportProgress(v);.

i tried to use 2 background worker instances, one executes and the other listens , it gives no errors but it seems do not call the event 'OutputDataReceived' so i don't see any progress in the progress bar.

below the code that i used:

    private void execute_script()
    {
             progress.bw.DoWork += new DoWorkEventHandler( //progress.bw is reference to the background worker instance
        delegate(object o, DoWorkEventArgs args)
        {

        System.Diagnostics.Process proc = new System.Diagnostics.Process();
        proc.StartInfo.FileName = "python.exe";
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.Arguments = @".\scripts\script1.py " + file_path + " " + txtscale.Text;
        //proc.StartInfo.CreateNoWindow = true;
        //proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
        proc.StartInfo.RedirectStandardOutput = true;
        //proc.EnableRaisingEvents = true;
        proc.StartInfo.RedirectStandardError = true;
        proc.StartInfo.RedirectStandardError = true; 
        proc.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(proc_OutputDataReceived);
        proc.Start();
        proc.BeginOutputReadLine();

      //proc.WaitForExit();
        //proc.Close();
                   });

           progress.bw.RunWorkerAsync();
        }

 ///the function called in the event OutputDataReceived 
 void proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
    {
        //throw new NotImplementedException();
        if (e.Data != null)
        {
            int v = Convert.ToInt32(e.Data.ToString()); 
            MessageBox.Show(v.ToString());
         //   report(v);
            progress.bw.ReportProgress(v);

        }
        else
            MessageBox.Show("null received"); 


    }

Upvotes: 5

Views: 9220

Answers (2)

Reed Copsey
Reed Copsey

Reputation: 564413

The problem is that the BackgroundWorker's DoWork handler finishes as soon as the process starts, as there's nothing "waiting" (since you commented out proc.WaitForExit()) for the process to finish. Once the BackgroundWorker work handler completes, you can no longer report progress using that instance.

Since Process.Start is already asynchronous, there is no reason to use a background worker at all. You can just marshal the call from OutputDataReceived onto the UI thread yourself:

///the function called in the event OutputDataReceived 
void proc_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
    //throw new NotImplementedException();
    if (e.Data != null)
    {
        int v = Convert.ToInt32(e.Data.ToString()); 
        // MessageBox.Show(v.ToString());
        // progress.bw.ReportProgress(v);
        this.BeginInvoke( new Action( () => {
             this.progressBar.Value = v;
        }));
    }
}

If you use this, don't create the BackgroundWorker at all.

Upvotes: 5

paparazzo
paparazzo

Reputation: 45096

BackGroundWorker has a ReportProgress option that is built just for this.

BackgroundWorker.ReportProgress Method (Int32, Object)

Upvotes: 0

Related Questions