BackgroundWorker 重たい処理のキャンセル 2005.NET
重たい処理がキャンセルできるようにするには、Application.DoEvents()をかまして行う方法があるが、
BackgroundWorkerコントロールができたのでこれを使う方法も選べるようになった。
BackgroundWorkerの良い点。
その名の通りバックグランドで行われるので実行中にフォームをクリックすると実行が止まる
ということがなくなり、よりスマートなUIが簡単に実現できるという点にあるようだ。
以下のサンプルはフォームにボタン2個、ラベル1個、
BackgroundWorkerコンポーネント1個(GUIからプロパティー 途中経過有効 キェンセル有効 をTrueにしたもの。)を追加して書いたもの
''Imports System.ComponentModel 'こいつをインポートしておいてもよい
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'スタートさせる
Me.Button1.Enabled = False '二重実行は厳禁なのでこうしておく
BackgroundWorker1.RunWorkerAsync(1000) 'これで重たい処理がバックグランドで実行される。
'1000は単なるパラメータ こうやって渡すことができる。
End Sub
Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'ここに重たい処理を書く
'ここで実行される処理は バックグランドで行われるので このルーチンからユーザインターフェイスは操作できない
'でも途中経過を知らなければバックグランドを使う意味がない。
'でコントロールにProgressChangedイベントがあるというわけ
'BackgroundWorker1.RunWorkerAsync(1000)の1000をiに取得する。
'ArgumentはHelpには非同期操作の引数を表す値を取得します。と書いてある。おまじないだ。
Dim i As Integer = CType(e.Argument, Integer)
Dim j As Integer = 0
'senderにバックグランドスレッド(オブジェクト)が入ってくるので取り出す。
Dim back As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
Do Until j = i
If back.CancellationPending = True Then
'キャンセルボタンが押されたか調査
e.Cancel = True
Exit Do
End If
' ''Application.DoEvents() 'これでは制御できない
' ''Application.DoEvents() 'これでは制御できない
' ''Application.DoEvents() 'これでは制御できない
' ''Application.DoEvents() 'これでは制御できない
' ''Application.DoEvents() 'これでは制御できない
' ''Application.DoEvents() 'これでは制御できない
' ''Application.DoEvents() 'これでは制御できない
System.Threading.Thread.Sleep(10) '指定したミリ秒数の間現在のスレッドをブロックします。これを書かないとキャンセルボタンは押せない
'ということはトータルの実行速度は遅くなる [1]だとキャンセルボタンは押せない 最小は[10]ぐらいか?
'0を指定すると途中停止になるらしいが止まらない
''Me.Label1.Text = j & "%" 'これはNG "有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'Label1' がアクセスされました。" が出る
back.ReportProgress(j) '何パーセント終了したか0~で入れるらしいが100を超えてもエラーは起きない Integerの2,147,483,647まで
j += 1 'インクリメント
Debug.WriteLine(j)
Loop
e.Result = "終了"
End Sub
Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
'途中経過の情報が入ってくる
Me.Label1.Text = e.ProgressPercentage & "%"
Debug.WriteLine(Me.Label1.Text)
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
'すべて終了したら入って来る
If e.Cancelled = True Then
Me.Label1.Text = "キャンセルしました"
Else
Me.Label1.Text = e.Result
End If
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
’キャンセルボタン
BackgroundWorker1.CancelAsync()
End Sub
End Class
|
|