処理のロジックは、まず同期処理として作成し、コンソールアプリケーションなどで動作を確認することが多いでしょう。
しかし、その処理をGUIアプリケーションから呼び出す場合、処理時間が長いとUIスレッドをブロックしてしまうため、非同期処理として実行する必要があります。
このような場合、処理本体は同期メソッドのままにしておき、それを非同期で実行する「非同期ラッパーメソッド」を用意することで、既存のコードを大きく変更せずにGUIアプリケーションへ組み込むことができます。
ソースコード
MainWindow.xaml
<Window x:Class="WpfSample01.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AsyncSample" Height="200" Width="300">
<StackPanel Margin="20">
<Button Name="StartButton"
Click="StartButton_Click"
Margin="0,0,0,10"
Content="開始" />
<Button Name="CancelButton"
Click="CancelButton_Click"
Margin="0,0,0,10"
Content="キャンセル" />
<TextBlock Name="StatusText"
FontSize="16"/>
</StackPanel>
</Window>
MainWindow.xaml.cs
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WpfSample01;
public partial class MainWindow : Window
{
CancellationTokenSource? _cts;
public MainWindow()
{
InitializeComponent();
}
private async void StartButton_Click(object sender, RoutedEventArgs e)
{
_cts = new CancellationTokenSource();
try
{
StatusText.Text = "処理中...";
await Worker.DoWorkAsync(_cts.Token);
StatusText.Text = "完了";
}
catch (OperationCanceledException)
{
StatusText.Text = "キャンセルされました";
}
finally
{
_cts.Dispose();
_cts = null;
}
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
_cts?.Cancel();
}
}
Worker.cs
using System.Threading;
using System.Threading.Tasks;
namespace WpfSample01;
public static class Worker
{
// 通常メソッド(同期)
public static void DoWork(CancellationToken token = default)
{
for (int i = 0; i < 10; i++)
{
token.ThrowIfCancellationRequested();
// 重い処理の代わり
Task.Delay(500, token).GetAwaiter().GetResult();
}
}
// Asyncラッパー(非同期)
public static Task DoWorkAsync(CancellationToken token = default)
{
return Task.Run(() => DoWork(token), token);
}
}
重い処理の代わりに、
Task.Delay() を使った少し見慣れないコードを書いていますが、
これはあくまでサンプル用の処理です。
実際のアプリケーションでは、この部分に 同期で実行される重たい処理(画像処理や計算処理など)を配置します。
今回の例では、その処理を非同期ラッパーメソッドから呼び出すことで、UIスレッドをブロックしない構成を説明しています。
実行例
起動後、「開始」ボタンを押すと処理が開始されます。

処理中に「キャンセル」ボタンを押すと、処理が途中でキャンセルされます。

一見すると何気ない動作ですが、処理の実行中でも「キャンセル」ボタンを押せるのは、
処理を非同期で実行しているためです。同期処理の場合、処理が終わるまでUIスレッドが
ブロックされるため、ボタン操作を受け付けることができません。

コメント