-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathTaskUtil.cs
More file actions
88 lines (76 loc) · 3.48 KB
/
Copy pathTaskUtil.cs
File metadata and controls
88 lines (76 loc) · 3.48 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
using System;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using ScrobbleMapper.Forms;
namespace ScrobbleMapper
{
static class TaskUtil
{
/// <summary>
/// Performs an asynchronous task in foreground (blocking the host form's user input) and reports its progress.
/// </summary>
/// <typeparam name="T">The task's result type</typeparam>
/// <param name="host">The host form</param>
/// <param name="taskContext">The task to perform</param>
/// <param name="onSuccess">What to do if the operation succeceeds; the parameter is the task's result</param>
/// <param name="onError">What to do if the operation fails; the parameter is the cause of the failure</param>
public static void PerformForegroundTask<T>(Form host, IReportingTask<T> taskContext, Action<T> onSuccess, Action<Exception> onError)
{
// Disable the host form (like ShowDialog would do)
host.Enabled = false;
var reporter = new ProgressReporter(taskContext);
reporter.Show(host);
// When the task completes,
taskContext.Task.ContinueWith(delegate
{
// Determine if there was an error
bool success = false;
bool canceled = taskContext.Task.IsCanceled;
Exception error = null;
if (!taskContext.Task.IsCanceled)
{
error = taskContext.Task.Exception;
// It really sucks to have an aggregate exception with a single inner...
while (error != null && error is AggregateException && (error as AggregateException).InnerExceptions.Count == 1)
error = error.InnerException;
// Target invocation exceptions are also meaningless wrappers
while (error != null && error is TargetInvocationException)
error = error.InnerException;
success = error == null;
}
// Bring back the host context (in its own thread)
bool enteredOnce = false;
Action bringBackHostContext = () =>
{
if (!enteredOnce)
{
enteredOnce = true;
reporter.Close();
reporter = null;
host.Enabled = true;
host.Focus();
// Execute the provided actions
if (success)
{
var result = taskContext.Task.Result;
taskContext.Dispose();
onSuccess(result);
}
else if (!canceled)
{
taskContext.Dispose();
onError(error);
}
}
};
// Try as many times as required, but only allow 1 execution of the action
IAsyncResult ar = host.BeginInvoke(bringBackHostContext);
while (!ar.AsyncWaitHandle.WaitOne(100, false) && !enteredOnce)
{
ar = host.BeginInvoke(bringBackHostContext);
}
});
}
}
}