有時候,任務的執行需要等待一段時間後再繼續進行。
下面的程式,彷效進出貨。進貨及出貨各需2.5秒,如果使用者按 Stop 鍵,程式就會「停止」。
Canecl2.xaml
<Window x:Class="TPL_CancelAnApp.Cancel2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Cancel2" Height="350" Width="525"> <Grid> <StackPanel > <TextBlock x:Name="txtTotal" /> <Button x:Name="btnStart" Click="btnStart_Click">Start</Button> <Button x:Name="btnStop" Click="btnStop_Click" Content="Stop"></Button> <TextBlock Name="txtStatus" /> </StackPanel> </Grid> </Window>
Cancel2.xaml.cs
using System; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; namespace TPL_CancelAnApp { public partial class Cancel2 : Window { //建立 CancellationTokenSource CancellationTokenSource tokenSource = new CancellationTokenSource(); Task task; public Cancel2() { InitializeComponent(); InitialTask(); } private void InitialTask() { CancellationToken token = tokenSource.Token; task = new Task(() => { long total = 0; while (total < int.MaxValue) { total++; Action<string> action = new Action<string>(s => txtTotal.Text = s); txtTotal.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal, total.ToString() + " 進貨"); Thread.Sleep(2500); txtTotal.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal, total.ToString() + " 出貨"); Thread.Sleep(2500); token.ThrowIfCancellationRequested(); }; }, token); } private void btnStart_Click(object sender, RoutedEventArgs e) { txtStatus.Text = "進行中"; task.Start(); btnStart.IsEnabled = false; } private void btnStop_Click(object sender, RoutedEventArgs e) { txtStatus.Text = "使用者要求停止"; tokenSource.Cancel(); } } }上面的程式是可以執行的。但有個問題,當使用者按 Stop 鍵,程式並不會立即停止,而是需要等到進貨及出貨完成(各2.5秒)後, 才到token.ThrowIfCancellationRequested這一行決定是否取消。因此,一定會出貨完。 有沒有方法可以立即停止呢?
更新
問題出在 Thread.Sleep(2500),是無論如何都會「睡」個 2.5 秒,與目前的 Task 無關。
此時,我們需要使用 CancellationToken.WaitHandle.WaitOne(2500) 來模擬了。程式會等待取消 2.5 秒,並回傳是否有被取消。
程式如下
private void InitialTask() { CancellationToken token = tokenSource.Token; task = new Task(() => { long total = 0; while (total < int.MaxValue) { total++; Action<string> action = new Action<string>(s => txtTotal.Text = s); txtTotal.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal, total.ToString() + " 進貨"); //Thread.Sleep(2500); bool isCanceled = false; isCanceled = token.WaitHandle.WaitOne(2500); if (isCanceled) token.ThrowIfCancellationRequested(); txtTotal.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal, total.ToString() + " 出貨"); //Thread.Sleep(2500); isCanceled = token.WaitHandle.WaitOne(2500); if (isCanceled) token.ThrowIfCancellationRequested(); }; }, token); }這樣修改後,按了Stop 鍵就會立即停止了。 範例程式下載
沒有留言:
張貼留言