WPFでTaskのキャンセルのサンプル

コンピュータ

ソースコード

ファイル名:MainWindow.xaml

<Window x:Class="TaskCancelSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Task Cancel Sample"
        Width="300"
        Height="200">

    <StackPanel Margin="20">
        <Button x:Name="StartButton"
                Content="開始"
                Click="Start_Click"
                Margin="0,0,0,10"/>

        <Button x:Name="CancelButton"
                Content="キャンセル"
                Click="Cancel_Click"
                IsEnabled="False"
                Margin="0,0,0,10"/>

        <TextBlock x:Name="StatusText"
                   Text="Idle"/>
    </StackPanel>
</Window>

ファイル名:MainWindow.xaml.cs

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace TaskCancelSample;

public partial class MainWindow : Window
{
    // キャンセルトークンソースの宣言
    private CancellationTokenSource? _cts;

    public MainWindow()
    {
        InitializeComponent();
    }
    // 開始ボタンクリック
    private async void Start_Click(object sender, RoutedEventArgs e)
    {
        StartButton.IsEnabled = false;  // 開始ボタン ... 無効
        CancelButton.IsEnabled = true;  // キャンセルボタン ... 有効
        StatusText.Text = "実行中...";

        // キャンセルトークンのインスタンス生成
        _cts = new CancellationTokenSource();   

        try
        {
            await Task.Run(() => HeavyWork(_cts.Token));
            StatusText.Text = "完了";
        }
        catch (OperationCanceledException)
        {
            StatusText.Text = "キャンセル済み";
        }
        finally
        {
            StartButton.IsEnabled = true;   // 開始ボタン ... 有効
            CancelButton.IsEnabled = false;  // キャンセルボタン ... 有効

            // キャンセルトークンソースの解放
            _cts.Dispose();
            _cts = null;
        }
    }
    // キャンセルボタンクリック
    private void Cancel_Click(object sender, RoutedEventArgs e)
    {
        // キャンセル発行
        _cts?.Cancel();
    }
    // 重たい処理。
    private void HeavyWork(CancellationToken token)
    {
        for (int i = 0; i < 10; i++)
        {
            // キャンセルリクエストでOperationCanceledExceptionをthrow
            token.ThrowIfCancellationRequested();

            // CPUを使う重たい処理の代わり
            Thread.Sleep(1000);

            // UI更新は Dispatcher 経由
            Dispatcher.Invoke(() =>
            {
                StatusText.Text = $"Step {i + 1}";
            });
        }
    }
}

実行例

  1. 実行ボタンを押す。
  2. カウントアップされる。
  3. キャンセルボタンを押す。→キャンセルされる

コメント