Modal Progress dialog with cancel for time-consuming operations, C#, WinForms


/ Published in: C#
Save to your folder(s)

Features/Requirements:\r\n\r\n[1] lightweight, easy-to-add\r\n[2] Display progress of long operation using (a) progress bar and (b) user-text.\r\n[3] Close dialog upon (a) Normal completion of long operation or (b) Cancel button used for early cancellation of long operation\r\n[4] GUI not hung/hourglassing during long operation. This can be done using threads or DoEvents. This example uses the BackgroundWorker class as a member of a Form.\r\n[5] Synchronized with no race conditions.\r\n\r\nThe form displayed consists of three elements: label, progress bar and a cancel button. The label auto-sizes so that user text will be displayed. The application constructs the dialog with parameters for titlebar text and a delegate for the long operation. The long operation reports progress using BackgroundWorker.ReportProgress. The long operation checks for cancellation using BackgroundWorker.CancellationPending\r\n\r\nSee code for example usage.


Copy this code and paste it in your HTML
  1. // Example usage:
  2. private void button4_Click(object sender, EventArgs e)
  3. {
  4. // Create dialog.
  5. ProgressWithCancel dlgProgress = new ProgressWithCancel( "Testing progress", LongOperation);
  6.  
  7. // Show dialog with Synchronous/blocking call.
  8. // LongOperation() is called by dialog.
  9. dlgProgress.ShowDialog(); // Synchronous/blocking call.
  10. }
  11.  
  12. private void LongOperation(object sender, DoWorkEventArgs e)
  13. {
  14. BackgroundWorker worker = sender as BackgroundWorker;
  15.  
  16. int max = 20;
  17. for (int i = 0; i < max; i++)
  18. {
  19. if (worker.CancellationPending) // See if cacel button was pressed.
  20. {
  21. System.Threading.Thread.Sleep(2000); // Similate time for clean-up.
  22. break;
  23. }
  24.  
  25. int percent = i * 100 / max;
  26.  
  27. string userState = percent.ToString(); // render a string to display on the progress dialog.
  28.  
  29. // Append to string just to show multi-line user-status info.
  30. if (percent >= 45 && percent <= 55) { userState += "Half way"; }
  31. if (percent >= 85) { userState += "Almost done"; }
  32.  
  33. worker.ReportProgress(percent, userState); // Report percent and user-status info to dialog.
  34.  
  35. System.Threading.Thread.Sleep(800); // Simulate time-consuming operation
  36. }
  37. }
  38.  
  39.  
  40. // Implementation (in ProgressWithCancel.cs)
  41.  
  42. namespace ProgressWithCancel
  43. {
  44. public partial class ProgressWithCancel : Form
  45. {
  46. public ProgressWithCancel(string whyWeAreWaiting, DoWorkEventHandler work)
  47. {
  48. InitializeComponent();
  49. this.Text = whyWeAreWaiting; // Show in title bar
  50. backgroundWorker1.DoWork += work; // Event handler to be called in context of new thread.
  51. }
  52.  
  53. private void btnCancel_Click(object sender, EventArgs e)
  54. {
  55. label1.Text = "Cancel pending";
  56. backgroundWorker1.CancelAsync(); // Tell worker to abort.
  57. btnCancel.Enabled = false;
  58. }
  59.  
  60. private void Progress_Load(object sender, EventArgs e)
  61. {
  62. backgroundWorker1.RunWorkerAsync();
  63. }
  64.  
  65. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
  66. {
  67. progressBar1.Value = e.ProgressPercentage;
  68. label1.Text = e.UserState as string;
  69. }
  70.  
  71. private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  72. {
  73. Close();
  74. }
  75.  
  76. }
  77. }
  78.  
  79.  
  80. // Designer (in ProgressWithCancel.designer.cs)
  81. namespace ProgressWithCancel
  82. {
  83. partial class ProgressWithCancel
  84. {
  85. /// <summary>
  86. /// Required designer variable.
  87. /// </summary>
  88. private System.ComponentModel.IContainer components = null;
  89.  
  90. /// <summary>
  91. /// Clean up any resources being used.
  92. /// </summary>
  93. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  94. protected override void Dispose(bool disposing)
  95. {
  96. if (disposing && (components != null))
  97. {
  98. components.Dispose();
  99. }
  100. base.Dispose(disposing);
  101. }
  102.  
  103. #region Windows Form Designer generated code
  104.  
  105. /// <summary>
  106. /// Required method for Designer support - do not modify
  107. /// the contents of this method with the code editor.
  108. /// </summary>
  109. private void InitializeComponent()
  110. {
  111. this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
  112. this.btnCancel = new System.Windows.Forms.Button();
  113. this.progressBar1 = new System.Windows.Forms.ProgressBar();
  114. this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
  115. this.label1 = new System.Windows.Forms.Label();
  116. this.tableLayoutPanel1.SuspendLayout();
  117. this.SuspendLayout();
  118. //
  119. // tableLayoutPanel1
  120. //
  121. this.tableLayoutPanel1.AutoSize = true;
  122. this.tableLayoutPanel1.ColumnCount = 1;
  123. this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
  124. this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
  125. this.tableLayoutPanel1.Controls.Add(this.btnCancel, 0, 2);
  126. this.tableLayoutPanel1.Controls.Add(this.progressBar1, 0, 1);
  127. this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
  128. this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
  129. this.tableLayoutPanel1.Name = "tableLayoutPanel1";
  130. this.tableLayoutPanel1.RowCount = 3;
  131. this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
  132. this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
  133. this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
  134. this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
  135. this.tableLayoutPanel1.Size = new System.Drawing.Size(292, 99);
  136. this.tableLayoutPanel1.TabIndex = 0;
  137. //
  138. // btnCancel
  139. //
  140. this.btnCancel.Anchor = System.Windows.Forms.AnchorStyles.Top;
  141. this.btnCancel.AutoSize = true;
  142. this.btnCancel.Location = new System.Drawing.Point(108, 60);
  143. this.btnCancel.Name = "btnCancel";
  144. this.btnCancel.Size = new System.Drawing.Size(75, 27);
  145. this.btnCancel.TabIndex = 0;
  146. this.btnCancel.Text = "Cancel";
  147. this.btnCancel.UseVisualStyleBackColor = true;
  148. this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
  149. //
  150. // progressBar1
  151. //
  152. this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));
  153. this.progressBar1.Location = new System.Drawing.Point(3, 34);
  154. this.progressBar1.Name = "progressBar1";
  155. this.progressBar1.Size = new System.Drawing.Size(286, 20);
  156. this.progressBar1.TabIndex = 1;
  157. //
  158. // backgroundWorker1
  159. //
  160. this.backgroundWorker1.WorkerReportsProgress = true;
  161. this.backgroundWorker1.WorkerSupportsCancellation = true;
  162. this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
  163. this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
  164. //
  165. // label1
  166. //
  167. this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
  168. | System.Windows.Forms.AnchorStyles.Left)
  169. | System.Windows.Forms.AnchorStyles.Right)));
  170. this.label1.AutoSize = true;
  171. this.label1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
  172. this.label1.Location = new System.Drawing.Point(3, 3);
  173. this.label1.Margin = new System.Windows.Forms.Padding(3);
  174. this.label1.Name = "label1";
  175. this.label1.Padding = new System.Windows.Forms.Padding(3);
  176. this.label1.Size = new System.Drawing.Size(286, 25);
  177. this.label1.TabIndex = 1;
  178. this.label1.Text = "label1";
  179. this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
  180. //
  181. // Progress
  182. //
  183. this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
  184. this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  185. this.AutoSize = true;
  186. this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
  187. this.ClientSize = new System.Drawing.Size(292, 99);
  188. this.ControlBox = false;
  189. this.Controls.Add(this.tableLayoutPanel1);
  190. this.Name = "Progress";
  191. this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
  192. this.Text = "Progress";
  193. this.Load += new System.EventHandler(this.Progress_Load);
  194. this.tableLayoutPanel1.ResumeLayout(false);
  195. this.tableLayoutPanel1.PerformLayout();
  196. this.ResumeLayout(false);
  197. this.PerformLayout();
  198.  
  199. }
  200.  
  201. #endregion
  202.  
  203. private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
  204. private System.Windows.Forms.Button btnCancel;
  205. public System.Windows.Forms.ProgressBar progressBar1;
  206. public System.ComponentModel.BackgroundWorker backgroundWorker1;
  207. private System.Windows.Forms.Label label1;
  208. }
  209. }

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.