Okno postępu do pracy w tle

Poniżej jest kod kompletnej klasy (bez potrzeby przygotowania okienka w trybie design) - dlatego konstruktor zawiera kod pełnej inicjalizacji formularza. Użyte kontrolki ProgressBar i Button do zatrzymania procesu. Dodatkowo formularz zawiera BackgroundWorker'a. Konstruktor jest prywatny. Publiczna jest tylko metoda Execute.

  public class Waiter : Form
  {
    public static void Execute(DoWorkEventHandler aDoWork, RunWorkerCompletedEventHandler aDoComplete)
    {
      Waiter f = new Waiter();
      f.doWork = aDoWork;
      f.doComplete = aDoComplete;
      f.ShowDialog();
    }

    DoWorkEventHandler doWork;
    RunWorkerCompletedEventHandler doComplete;

    private BackgroundWorker backgroundWorker1;
    private Button btnCancel;
    private ProgressBar progressBar1;    
    
    private void btnCancel_Click(object sender, EventArgs e)
    {
      backgroundWorker1.CancelAsync();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
      if (doWork != null)
        doWork(sender, e);
    }

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

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      if (doComplete != null)
        doComplete(sender, e);
      Close();
    }

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

    private Waiter()
    {
      backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
      btnCancel = new System.Windows.Forms.Button();
      progressBar1 = new ProgressBar();
      backgroundWorker1.WorkerReportsProgress = true;
      backgroundWorker1.WorkerSupportsCancellation = true;
      backgroundWorker1.DoWork += backgroundWorker1_DoWork;
      backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
      backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;
      btnCancel.Location = new Point(182, 61);
      btnCancel.Size = new Size(90, 31);
      btnCancel.Text = "Anuluj";
      btnCancel.UseVisualStyleBackColor = true;
      btnCancel.Click += btnCancel_Click;
      progressBar1.Location = new Point(0, 0);
      progressBar1.Size = new System.Drawing.Size(283, 55);
      AutoScaleDimensions = new SizeF(6F, 13F);
      ClientSize = new System.Drawing.Size(284, 96);
      ControlBox = false;
      Controls.Add(progressBar1);
      Controls.Add(btnCancel);
      FormBorderStyle = FormBorderStyle.FixedToolWindow;
      StartPosition = FormStartPosition.CenterScreen;
      Text = "Proszę czekać ...";
      Load += ProgressForm_Load;
    }
  }

BackgroundWorker ma na "tak" ustawione właściwości odpowiedzialne za zdolność raportowania postępu i przerwania pracy.
Metoda Execute otrzymuje dwa parametry:

public static void Execute(DoWorkEventHandler aDoWork, RunWorkerCompletedEventHandler aDoComplete)

aDoWork to procedura wykonująca właściwe zadanie, a aDoComplete to procedura wykonywana na zakonczenie pracy.
Oto kod przykładowego zastosowania. Proces startuje w efekcie zdarzenia Click obsługiwanego przez button1_Click.

 
    private void button1_Click(object sender, EventArgs e)
    {
      Waiter.Execute(work, complete);
    }

    private void work(object sender, DoWorkEventArgs e)
    {
      BackgroundWorker bg = sender as BackgroundWorker;
      for (int i = 0; i <= 10; i++)
      {
        DateTime t = DateTime.Now.AddMilliseconds(500);
        while (DateTime.Now < t) { }
        bg.ReportProgress(i * 10);
        if (bg.CancellationPending)
        {
          e.Cancel = true;
          break;
        }
      }
    }

    private void complete(object sender, RunWorkerCompletedEventArgs e)
    {
      if (e.Cancelled)
        MessageBox.Show("Przerwano");
      else
        MessageBox.Show("Gotowe");
    }    

Procedura work symuluje wykonanie czasochłonnego zadania.
W ramach pętli BackgroundWorker otrzymuje żądanie wykazania postępu:

bg.ReportProgress(i * 10);

oraz sprawdzany jest na okoliczność żądania zaprzestania realizacji zadania:

        if (bg.CancellationPending)
        {
          e.Cancel = true;
          break;
        }

Samo żądanie zgłaszane jest poprzez obsługę zdarzenia Click przycisku "Anuluj" w klasie Waiter.

    private void btnCancel_Click(object sender, EventArgs e)
    {
      backgroundWorker1.CancelAsync();
    }

Procedura complete potrafi rozpoznać w jaki sposób praca została zakończona przez sprawdzenie parametru e.Cancelled.