有時候,任務的執行需要等待一段時間後再繼續進行。
下面的程式,彷效進出貨。進貨及出貨各需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 鍵就會立即停止了。
範例程式下載
沒有留言:
張貼留言