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.