動作環境
Windows 8.1 Pro (64bit)
Microsoft Visual Studio 2017 Community
Sublime Text 2
関連: Visual Studio | WPF > 非同期処理 > Link: ざっくりマルチスレッド(非同期処理)
処理概要
- Startボタン: Taskを開始
- Cancelボタン: Taskをキャンセル
- Start後に設定時間経過後にTaskが終了
- Taskクラスを用いた実装
参考
Task クラス
Task.Wait メソッド (CancellationToken)
code v0.1
MainWindow.xaml
<Window x:Class="_171220_t1320_taskCancel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:_171220_t1320_taskCancel"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<Button Name="B_start" Content="Start" Height="30"
Click="B_start_Click"/>
<Button Name="B_cancel" Content="Cancel" Height="30"
Click="B_cancel_Click"/>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// 以下を追加した
using System.Threading;
namespace _171220_t1320_taskCancel
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
private bool bfStop = false;
public MainWindow()
{
InitializeComponent();
}
private void B_start_Click(object sender, RoutedEventArgs e)
{
bfStop = false;
Task tsk = Task.Run(() => WaitTask());
}
private void WaitTask()
{
using (var cts = new CancellationTokenSource())
{
Task tsk = Task.Run(() => SubTask(cts));
try
{
Console.WriteLine("Task wait");
tsk.Wait(cts.Token);
}
catch (OperationCanceledException exc)
{
Console.WriteLine("Canceled: {0}", exc.Message);
}
}
}
private void SubTask(CancellationTokenSource cts)
{
for(int loop=0; loop<10; loop++)
{
Task.Delay(1000).Wait(); // msec
if (bfStop)
{
cts.Cancel();
return;
}
}
Console.WriteLine("Task ended");
}
private void B_cancel_Click(object sender, RoutedEventArgs e)
{
bfStop = true;
}
}
}
実行例
- Startボタン押下, Cancelボタン押下
- Startボタン押下, Cancelボタン押下
- Startボタン押下, 放置
備考
- B_start_Click()内でtsk.Wait()するとCancelボタンが使用できない
- 処理を抜けていないから
- 上記の実装が「標準的か」はもっといろいろ実装してからでないと分からない
- async, awaitはそのうち勉強する
- Task tskの宣言位置は変更した方がいいかもしれない
- usingステートメントにはtry, catchをした方がいいかもしれない: 関連
code v0.2
async/awaitについての備忘録 by @mounntainn さん
を参考にB_cancel_Clickの処理を変更してみた。
- bfStop廃止
- B_cancel_Click()にてcts.Cancel()実行
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// 以下を追加した
using System.Threading;
namespace _171220_t1320_taskCancel
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
private CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private void B_start_Click(object sender, RoutedEventArgs e)
{
Task tsk = Task.Run(() => WaitTask());
}
private void WaitTask()
{
cts = new CancellationTokenSource();
Task tsk = Task.Run(() => SubTask(cts));
try
{
Console.WriteLine("Task wait");
tsk.Wait(cts.Token);
}
catch (OperationCanceledException exc)
{
Console.WriteLine("Canceled: {0}", exc.Message);
}
cts.Dispose();
}
private void SubTask(CancellationTokenSource cts)
{
for(int loop=0; loop<10; loop++)
{
Task.Delay(1000).Wait(); // msec
if (cts.IsCancellationRequested)
{
return;
}
}
Console.WriteLine("Task ended");
}
private void B_cancel_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
}
}
}
v0.1と比べてCancel処理が早くなったようだ。
WPFメモ 非同期キャンセル処理 画面サンプル by @Kosen-amai さんの記事にもフラグ処理とトークン処理の違いが紹介されている。
#region
左側の処理(キャンセル押してから終了するまでにタイムラグあり)