Repository navigation
Expand file tree
/
Copy pathFactorialDialog.cs
More file actions
162 lines (147 loc) · 5.6 KB
/
Copy pathFactorialDialog.cs
File metadata and controls
162 lines (147 loc) · 5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
using System;
using System.Drawing;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Forms;
namespace async
{
public partial class FactorialDialog : Form
{
CancellationTokenSource m_cancellation_token_source;
public FactorialDialog()
{
InitializeComponent();
}
#region Button Handlers
// Note that this method has to be decorated with async, otherwise I can't
// call async methods inside it.
private async void buttonCompute_Click(object sender, EventArgs e)
{
// Initialize the Result field to show we're computing.
labelResult.Text = "Wait...";
Int64 n = Convert.ToInt32(txtInput.Text);
Int64 result = 0;
Progress<Int64> progress = new Progress<Int64>();
switch (comboComputeMethod.Text)
{
case "Synchronous":
// Notice how the UI is unresponsive when using this call.
result = ComputeFactorial(n, null, CancellationToken.None);
labelResult.Text = "Answer: " + result.ToString();
return;
case "Asynchronous":
// Here we have a responsive UI, but no indication of progress, and no way to cancel.
result = await ComputeFactorialAsync(n);
break;
case "Async with Progress":
progress.ProgressChanged += ProgressChanged;
result = await ComputeFactorialAsync(n, progress);
break;
case "Async with Progress and Cancel":
progress.ProgressChanged += ProgressChanged;
m_cancellation_token_source = new CancellationTokenSource();
try
{
buttonCancel.Enabled = true;
result = await ComputeFactorialAsync(n, progress, m_cancellation_token_source.Token);
}
catch (OperationCanceledException)
{
labelResult.Text = "Computation Cancelled";
progress.ProgressChanged -= ProgressChanged;
return;
}
finally
{
buttonCancel.Enabled = false;
}
break;
}
// Display the answer.
labelResult.Text = "Answer: " + result.ToString();
}
/// <summary>
/// Handler for progress reports while computing Factorial
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void ProgressChanged(object sender, Int64 e)
{
labelResult.Text = "Computing... " + e.ToString();
}
/// <summary>
/// Toggle background color of the form. This is useful to test if the UI is still alive.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void buttonChangeBackground_Click(object sender, EventArgs e)
{
this.BackColor = this.BackColor == Color.White ? Color.Gainsboro : Color.White;
}
// Handler for cancel button.
private void buttonCancel_Click(object sender, EventArgs e)
{
if (m_cancellation_token_source != null)
m_cancellation_token_source.Cancel();
}
#endregion
/// <summary>
/// Compute Factorial of n on a separate thread.
/// </summary>
/// <param name="n">Number to compute factorial from</param>
/// <returns>The factorial of input 'n'</returns>
Task<Int64> ComputeFactorialAsync(Int64 n)
{
return Task.Run(
() => ComputeFactorial(n, null, CancellationToken.None)
);
}
/// <summary>
/// Compute Factorial of n on a separate thread and report progress.
/// </summary>
/// <param name="n">Number to compute factorial from</param>
/// <param name="progress">Optional class to report progress. Pass null if you don't care to receive progress.</param>
/// <returns>The factorial of input 'n'</returns>
Task<Int64> ComputeFactorialAsync(Int64 n, IProgress<Int64> progress)
{
return Task.Run(
() => ComputeFactorial(n, progress, CancellationToken.None)
);
}
/// <summary>
/// Compute Factorial of n on a separate thread, supporting cancellation and reporting of progress.
/// </summary>
/// <param name="n">Number to compute factorial from</param>
/// <param name="progress">Optional class to report progress. Pass null if you don't care to receive progress.</param>
/// <param name="cancellationToken">Optional CancellationToken. Pass CancellationToken.None if you don't care to cancel.</param>
/// <returns>The factorial of input 'n'</returns>
Task<Int64> ComputeFactorialAsync(Int64 n, IProgress<Int64> progress, CancellationToken cancellationToken)
{
return Task.Run(
() => ComputeFactorial(n, progress, cancellationToken)
);
}
/// <summary>
/// ComputeFactorial is a time consuming function (mostly because it sleeps for half a second at each iteration)
/// that reports progress and optionally can be cancelled.
/// </summary>
/// <param name="n">Number to compute factorial from</param>
/// <param name="progress">Optional class to report progress. Pass null if you don't care to receive progress.</param>
/// <param name="cancellationToken">Optional CancellationToken. Pass CancellationToken.None if you don't care to cancel.</param>
/// <returns>The factorial of input 'n'</returns>
Int64 ComputeFactorial(Int64 n, IProgress<Int64> progress, CancellationToken cancellationToken)
{
Int64 result = 1;
for (Int64 i = n; i > 1; i--)
{
Thread.Sleep(500);
result *= i;
if (progress != null)
progress.Report(result);
if (cancellationToken.IsCancellationRequested)
throw new OperationCanceledException();
}
return result;
}
}
}