若想要讓產生的Task具有可取消的機制,則必需透過以下static methods取得task handle與傳入cancel token來達成
Task.Run(Action, CancellationToken)
Task.Run(Func<Task>, CancellationToken)
Task.Run<TResult>(Func<Task<TResult>>, CancellationToken)
Task.Run<TResult>(Func<TResult>, CancellationToken)
這個範例是我設計的一個對話盒控制項,當對話盒產生時呼叫InitItemsAsync以非同步的方式產生圖片對載入UI的list控制項中,使用者可以不必等待所有的圖片都產生即按下OK(或Cancel)按來關閉這個對話盒。因此我必需讓InitItemsAsync具有可被取消的機制。
1: public sealed partial class MyDialog : UserControl
2: {
3: private CancellationTokenSource _cts;
4: private CancellationToken _token;
5: private Task _opInit;
#3-5 我們的物件必需儲存CancellationTokenSource、CancellationToken與Task方便在動作的對應函式中取消
1: private async Task InitItemsAsync()
2: {
3: for(int i=0 ; i<24 ; i++)
4: {
5: if (_token.IsCancellationRequested) break;
6:
7: await LoadImageAsync(i);
8: }
9: }
#5 非同步的InitItemsAsync函式,當_token收到取消的要求時(IsCancellationRequested)提前結束迴圈
1: _cts = new CancellationTokenSource();
2: _token = _cts.Token;
3: _opInit = Task.Run(async () =>
4: {
5: await InitItemsAsync();
6: },
7: _token);
透過Task.Run來執行非同步的函式,並載入cancel token。
#5 InitItemAsync是非同步的函式,因此必需有async / await來載明
PS: 我嘗試過不用Lambda的寫法,而是直接以函式指標的方式來使用Task.Run,但在VS2013編譯時期會有函式型別模糊(error CS0121: The call is ambiguous between the following methods or properties)的錯誤,目前還不知道解決的方式。
1: private bool TryCancelInitItems()
2: {
3: if (_opInit.IsCompleted == false)
4: {
5: try
6: {
7: _cts.Cancel();
8:
9: _opInit.Wait(_token);
10:
11: return true;
12: }
13: catch(System.OperationCanceledException)
14: {
15: return true;
16: }
17: catch (Exception e)
18: {
19: Debug.WriteLine(@"{0}", e);
20:
21: return false;
22: }
23: }
24:
25: return true;
26: }
#3 先檢查task是否已經完成,若尚未完成才需使用取消機制
#7 呼叫取消並等待_token
#13 若InitItemsAsync被取消了,會丟出System.OperationCanceledException