Search code examples
c#backgroundworker

BackgroundWorker not exiting loop


I have an BackgroundWorker: BackgroundWorker worker;

private void Form1_Load(object sender, EventArgs e)
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;

worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += 
          new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerCompleted += 
         new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
}

DoWork Event

void worker_DoWork(object sender, DoWorkEventArgs e)
{
int percentFinished = (int)e.Argument;
while (!worker.CancellationPending && percentFinished < 100)
{
 percentFinished++;
 worker.ReportProgress(percentFinished);

 //here I start my operation
 //operation....
 //operation end

}
e.Result = percentFinished;
}

Progresschanged

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

Completed

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Asynchroner Thread kam bis zum Wert:
"+e.Result.ToString());
btnStartEnd.Text = "Starten";
}

And finally my button:

private void btnStartEnd_Click(object sender, EventArgs e)
{
   if (worker.IsBusy)
   {
   worker.CancelAsync();
   btnStartEnd.Text = "Starten";
   }
else
   {
     if (progressBar1.Value == progressBar1.Maximum)
      {
      progressBar1.Value = progressBar1.Minimum;
      }
    worker.RunWorkerAsync(progressBar1.Value);
    btnStartEnd.Text = "Stoppen";
   }
}

This code works but I get a loop for my operations until the percentage is 100, so the operation starts 100 times and so takes 100 times longer.

The goal should be that the operation only starts one time and the percentage counts from 1-100.

Maybe I understand something wrong, but how does the worker know how far the operation is done? That value should be send to the progress bar for visualisation.


Solution

  • Normally you won’t add the loop inside the DoWork method If you want to load for example 100 files from the file system and report the progress it could look like that:

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        for(int i = 0; i < 100; i++)
        {
            // Load file and do something with the content
            ...
            // Report the progress which causes the ProgressChanged event to be fired
            // And update progressbar with the UI thread
            worker.ReportProgress(i);                   
        }
    }
    

    If you only have one long running operation that needs to be executed inside the DoWork method it needs to be executed asynchronously

    Here is one example how you could call an action asynchronously in .NET:

    Action action = () =>
    {
        for(int i = 0; i <100; i++)
        {
            Console.WriteLine(String.Format("Step {0} of long running operation", i));
            Thread.Sleep(1000);
        }
    };
    
    var r = action.BeginInvoke(null, null);
    while(!r.IsCompleted)
    {
        Console.WriteLine("Waiting...");
        Thread.Sleep(100);
    }
    

    However in .NET there are many more ways to do it. See for example: