Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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"); 


    }
like image 403
geogeek Avatar asked Aug 09 '12 19:08

geogeek


1 Answers

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.

like image 188
Reed Copsey Avatar answered Sep 26 '22 03:09

Reed Copsey