若想要讓產生的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