|
.NET TIPS
バックグラウンド処理を途中でキャンセルするには?[2.0のみ、C#、VB]
デジタルアドバンテージ 遠藤 孝信
2006/04/14 |
|
|
「TIPS:時間のかかる処理をバックグラウンドで実行するには?」では、BackgroundWorkerコンポーネントの基本的な利用方法について解説した。本稿では、バックグラウンド(別スレッド)で実行されている、時間のかかる処理(以下、重い処理)のキャンセル方法について解説する。
なお本稿では、前掲のTIPSのサンプル・アプリケーションに[キャンセル]ボタンを追加しながら、BackgroundWorkerコンポーネントのキャンセル処理の実装について説明する。
WorkerSupportsCancellationプロパティの設定
まずはサンプル・アプリケーションのフォームに[キャンセル]ボタンを追加する。このボタンはバックグラウンド処理を実行中にのみクリック可能とするため、プロパティ・ウィンドウでEnableプロパティをfalseに設定しておく(Nameプロパティは「buttonCancel」に設定)。
また、バックグラウンド処理をキャンセル可能にするために、すでに配置済みのBackgroundWorkerコンポーネントに対して、WorkerSupportsCancellationプロパティをtrueに設定しておく必要がある。
|
[キャンセル]ボタンを追加したWindowsフォーム |
バックグラウンド処理をキャンセル可能にするために、BackgroundWorkerコンポーネントのWorkerReportsProgressプロパティをtrueに設定しておく。 |
BackgroundWorkerコンポーネントのキャンセル処理
BackgroundWorkerコンポーネントにおけるキャンセル処理の流れは以下のようになる。
- BackgroundWorkerコンポーネントのCancelAsyncメソッドを呼び出す。これにより、BackgroundWorkerコンポーネントのCancellationPendingプロパティがtrueに設定される。
- 重い処理を行っているDoWorkイベント・ハンドラでは、CancellationPendingプロパティがtrueに設定されていないか(=キャンセルが要求されていないか)を定期的にチェックし、trueになっていれば「e.Cancel」*1をtrueに設定して、DoWorkイベント・ハンドラを抜ける(これによりRunWorkerCompletedイベント・ハンドラが実行される)。
- 上記2でe.Cancelをtrueに設定して重い処理をキャンセルした場合、RunWorkerCompletedイベント・ハンドラでは「e.Canceled」*2にtrueが設定される。この場合にはキャンセル時の後処理を(もしあれば)行う。キャンセルされていない場合には、e.Canceledはfalseとなる。
*1 「e」はDoWorkEventArgsクラスのオブジェクト。
*2 「e」はRunWorkerCompletedEventArgsクラスのオブジェクト。
※ いずれのクラスもSystem.ComponentModel名前空間に属する。
|
キャンセル処理を追加したサンプル・アプリケーション
以下に、キャンセル処理を追加したサンプル・アプリケーションのソース・コードを示す(Form1.cs/Form1.vbのみ)。変更を行っていないコードはグレーで示している。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace BGWorker1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
// [スタート]ボタンのイベント・ハンドラ
private void buttonStart_Click(object sender, EventArgs e) {
buttonStart.Enabled = false;
buttonCancel.Enabled = true;
// 時間のかかる処理を別スレッドで開始
bgWorker.RunWorkerAsync(100);
// DoWorkイベント発生
}
// [キャンセル]ボタンのイベント・ハンドラ
private void buttonCancel_Click(object sender, EventArgs e) {
// 時間のかかる処理のキャンセル
bgWorker.CancelAsync();
}
// 時間のかかる処理を行うメソッド
private void bgWorker_DoWork(object sender, DoWorkEventArgs e) {
// 別スレッドで実行されるため、このメソッドでは
// UI(コントロール)を操作してはいけない
// このメソッドへのパラメータ
int bgWorkerArg = (int)e.Argument;
// senderの値はbgWorkerの値と同じ
BackgroundWorker worker = (BackgroundWorker)sender;
// 時間のかかる処理
for (int i = 0; i < bgWorkerArg; i++) {
// キャンセルされてないか定期的にチェック
if (worker.CancellationPending) {
e.Cancel = true;
return;
}
System.Threading.Thread.Sleep(100);
int percentage = i * 100 / bgWorkerArg; // 進ちょく率
worker.ReportProgress(percentage);
// ProgressChangedイベント発生
}
// このメソッドからの戻り値
e.Result = "すべて完了";
// この後、RunWorkerCompletedイベントが発生
}
private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
// 進ちょく状況の表示
this.Text = e.ProgressPercentage + "%完了";
progressBar.Value = e.ProgressPercentage;
}
private void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Cancelled) {
MessageBox.Show("キャンセルされました");
// この場合にはe.Resultにはアクセスできない
} else {
// 処理結果の表示
this.Text = e.Result.ToString();
MessageBox.Show("正常に完了");
}
buttonStart.Enabled = true;
buttonCancel.Enabled = false;
}
}
}
|
Imports System.ComponentModel
Public Class Form1
' [スタート]ボタンのイベント・ハンドラ
Private Sub buttonStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonStart.Click
buttonStart.Enabled = False
buttonCancel.Enabled = True
' 時間のかかる処理を別スレッドで開始
bgWorker.RunWorkerAsync(100)
' DoWorkイベント発生
End Sub
' [キャンセル]ボタンのイベント・ハンドラ
Private Sub buttonCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonCancel.Click
' 時間のかかる処理のキャンセル
bgWorker.CancelAsync()
End Sub
' 時間のかかる処理を行うメソッド
Private Sub bgWorker_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bgWorker.DoWork
' 別スレッドで実行されるため、このメソッドでは
' UI(コントロール)を操作してはいけない
' このメソッドへのパラメータ
Dim bgWorkerArg As Integer = CType(e.Argument, Integer)
' senderの値はbgWorkerの値と同じ
Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
' 時間のかかる処理
For i As Integer = 1 To bgWorkerArg
' キャンセルされてないか定期的にチェック
If worker.CancellationPending Then
e.Cancel = True
Return
End If
System.Threading.Thread.Sleep(100)
Dim percentage As Integer = i * 100 / bgWorkerArg ' 進ちょく率
worker.ReportProgress(percentage)
' ProgressChangedイベント発生
Next
' このメソッドからの戻り値
e.Result = "すべて完了"
' この後、RunWorkerCompletedイベントが発生
End Sub
Private Sub bgWorker_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles bgWorker.ProgressChanged
' 進ちょく状況の表示
Me.Text = e.ProgressPercentage & "%完了"
progressBar.Value = e.ProgressPercentage
End Sub
Private Sub bgWorker_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles bgWorker.RunWorkerCompleted
If e.Cancelled Then
MessageBox.Show("キャンセルされました")
' この場合にはe.Resultにはアクセスできない
Else
' 処理結果の表示
Me.Text = e.Result.ToString()
MessageBox.Show("正常に完了")
End If
buttonStart.Enabled = True
buttonCancel.Enabled = False
End Sub
End Class
|
|
キャンセル処理を追加したサンプル・プログラム(上:Form1.cs、下:Form1.vb) |
CancelAsyncメソッドを呼び出しても、あるいはDoWorkイベント・ハンドラで「e.Cancel」をtrueに設定しても、重い処理が自動的に中断されるわけではない点に少し注意が必要だ。
キャンセルを行った場合、RunWorkerCompletedイベント・ハンドラでは、処理結果を示す「e.Result」の値にはアクセスできない点にも注意してほしい(アクセスすると例外が発生する)。
利用可能バージョン:.NET Framework 2.0のみ
カテゴリ:Windowsフォーム 処理対象:スレッド
使用ライブラリ:BackgroundWorkerコンポーネント(System.ComponentModel名前空間)
使用ライブラリ:DoWorkEventArgsクラス(System.ComponentModel名前空間)
使用ライブラリ:ProgressChangedEventArgsクラス(System.ComponentModel名前空間)
使用ライブラリ:RunWorkerCompletedEventArgsクラス(System.ComponentModel名前空間)
関連TIPS:時間のかかる処理をバックグラウンドで実行するには?
|
|
generated by
|
|
Insider.NET 記事ランキング
本日
月間