Posted By

jimfred on 07/06/10


Tagged


Versions (?)

Who likes this?

3 people have marked this snippet as a favorite

khouser
Tyster
Priestd09


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


 / Published in: C#
 

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.

  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  

You need to login to post a comment.