LoginSignup
0
1

More than 5 years have passed since last update.

Visual Studio | WPF > Taskクラス > Startボタン, Cancelボタンでのタスクの開始、キャンセル処理 v0.1, v0.2

Last updated at Posted at 2017-12-20
動作環境
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ボタン押下, 放置

qiita.png

備考

  • 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 左側の処理(キャンセル押してから終了するまでにタイムラグあり)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1