/
ProgressReporter.cs
157 lines (144 loc) · 8.4 KB
/
ProgressReporter.cs
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
using System;
using System.Threading;
using System.Threading.Tasks;
namespace RummageCore
{
/// <summary>
/// A class used by Tasks to report progress or completion updates back to the UI.
/// </summary>
/// <remarks>Taken from "Reporting Progress from Tasks" blog post available here:
/// http://nitoprograms.blogspot.com/2010/06/reporting-progress-from-tasks.html
/// </remarks>
public sealed class ProgressReporter
{
/// <summary>
/// The underlying scheduler for the UI's synchronization context.
/// </summary>
private readonly TaskScheduler scheduler;
/// <summary>
/// Initializes a new instance of the <see cref="ProgressReporter"/> class.
/// This should be run on a UI thread.
/// </summary>
public ProgressReporter()
{
this.scheduler = TaskScheduler.Default;
//this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
}
/// <summary>
/// Gets the task scheduler which executes tasks on the UI thread.
/// </summary>
public TaskScheduler Scheduler
{
get { return this.scheduler; }
}
/// <summary>
/// Reports the progress to the UI thread. This method should be called from the task.
/// Note that the progress update is asynchronous with respect to the reporting Task.
/// For a synchronous progress update, wait on the returned <see cref="Task"/>.
/// </summary>
/// <param name="action">The action to perform in the context of the UI thread.
/// Note that this action is run asynchronously on the UI thread.</param>
/// <returns>The task queued to the UI thread.</returns>
public Task ReportProgressAsync(Action action)
{
return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, this.scheduler);
}
/// <summary>
/// Reports the progress to the UI thread, and waits for the UI thread to process
/// the update before returning. This method should be called from the task.
/// </summary>
/// <param name="action">The action to perform in the context of the UI thread.</param>
public void ReportProgress(Action action)
{
this.ReportProgressAsync(action).Wait();
}
/// <summary>
/// Registers a UI thread handler for when the specified task finishes execution,
/// whether it finishes with success, failiure, or cancellation.
/// </summary>
/// <param name="task">The task to monitor for completion.</param>
/// <param name="action">The action to take when the task has completed, in the context of the UI thread.</param>
/// <returns>The continuation created to handle completion. This is normally ignored.</returns>
public Task RegisterContinuation(Task task, Action action)
{
return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.None, this.scheduler);
}
/// <summary>
/// Registers a UI thread handler for when the specified task finishes execution,
/// whether it finishes with success, failiure, or cancellation.
/// </summary>
/// <typeparam name="TResult">The type of the task result.</typeparam>
/// <param name="task">The task to monitor for completion.</param>
/// <param name="action">The action to take when the task has completed, in the context of the UI thread.</param>
/// <returns>The continuation created to handle completion. This is normally ignored.</returns>
public Task RegisterContinuation<TResult>(Task<TResult> task, Action action)
{
return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.None, this.scheduler);
}
/// <summary>
/// Registers a UI thread handler for when the specified task successfully finishes execution.
/// </summary>
/// <param name="task">The task to monitor for successful completion.</param>
/// <param name="action">The action to take when the task has successfully completed, in the context of the UI thread.</param>
/// <returns>The continuation created to handle successful completion. This is normally ignored.</returns>
public Task RegisterSucceededHandler(Task task, Action action)
{
return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this.scheduler);
}
/// <summary>
/// Registers a UI thread handler for when the specified task successfully finishes execution
/// and returns a result.
/// </summary>
/// <typeparam name="TResult">The type of the task result.</typeparam>
/// <param name="task">The task to monitor for successful completion.</param>
/// <param name="action">The action to take when the task has successfully completed, in the context of the UI thread.
/// The argument to the action is the return value of the task.</param>
/// <returns>The continuation created to handle successful completion. This is normally ignored.</returns>
public Task RegisterSucceededHandler<TResult>(Task<TResult> task, Action<TResult> action)
{
return task.ContinueWith(t => action(t.Result), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this.Scheduler);
}
/// <summary>
/// Registers a UI thread handler for when the specified task becomes faulted.
/// </summary>
/// <param name="task">The task to monitor for faulting.</param>
/// <param name="action">The action to take when the task has faulted, in the context of the UI thread.</param>
/// <returns>The continuation created to handle faulting. This is normally ignored.</returns>
public Task RegisterFaultedHandler(Task task, Action<Exception> action)
{
return task.ContinueWith(t => action(t.Exception), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, this.Scheduler);
}
/// <summary>
/// Registers a UI thread handler for when the specified task becomes faulted.
/// </summary>
/// <typeparam name="TResult">The type of the task result.</typeparam>
/// <param name="task">The task to monitor for faulting.</param>
/// <param name="action">The action to take when the task has faulted, in the context of the UI thread.</param>
/// <returns>The continuation created to handle faulting. This is normally ignored.</returns>
public Task RegisterFaultedHandler<TResult>(Task<TResult> task, Action<Exception> action)
{
return task.ContinueWith(t => action(t.Exception), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, this.Scheduler);
}
/// <summary>
/// Registers a UI thread handler for when the specified task is cancelled.
/// </summary>
/// <param name="task">The task to monitor for cancellation.</param>
/// <param name="action">The action to take when the task is cancelled, in the context of the UI thread.</param>
/// <returns>The continuation created to handle cancellation. This is normally ignored.</returns>
public Task RegisterCancelledHandler(Task task, Action action)
{
return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);
}
/// <summary>
/// Registers a UI thread handler for when the specified task is cancelled.
/// </summary>
/// <typeparam name="TResult">The type of the task result.</typeparam>
/// <param name="task">The task to monitor for cancellation.</param>
/// <param name="action">The action to take when the task is cancelled, in the context of the UI thread.</param>
/// <returns>The continuation created to handle cancellation. This is normally ignored.</returns>
public Task RegisterCancelledHandler<TResult>(Task<TResult> task, Action action)
{
return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);
}
}
}