C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: 別スレッド動作中に親フォームを終了させるとエラ


(過去ログ 77 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■45612 / inTopicNo.1)  別スレッド動作中に親フォームを終了させるとエラー
  
□投稿者/ えれこぜ (1回)-(2010/01/15(Fri) 18:59:56)

分類:[VB.NET/VB2005 以降] 

お世話になります。えれこぜと申します。
VB2005を使用して、別スレッドから親フォームのラベルコントロールを操作するプログラムを作成しています。
別スレッドの動作中に親フォームを終了させると、かなりの頻度でエラーが発生してしまいます。

ObjectDisposedException
破棄されたオブジェクトにアクセスできません。
オブジェクト名 'Form1' です。

親フォームが破棄されていたら、メソッドを抜けるようにしましたが、
あまり意味がないようで、エラーが発生してしまいます。

'親フォーム
Public Class Form1
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If Not BackgroundWorker1.IsBusy Then
            BackgroundWorker1.RunWorkerAsync()
        End If
    End Sub

    Public Delegate Sub Label1ValueDelegate(ByVal str As String)
    Public Sub Label1_Value(ByVal str As String)
        If Me.IsDisposed Then
            Return
        End If
        If Me.InvokeRequired Then
            Me.Invoke(New Label1ValueDelegate(AddressOf Label1_Value), str) 'ここでエラーが発生します!
        End If
        Me.Label1.Text = str
    End Sub

    Private Sub BackgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim hoge As New hoge(Me)
        hoge.DisplayMessage()
    End Sub
End Class

'別スレッド
Public Class hoge
    Private _form As Form1
    Sub New(ByVal form As Form1)
        Me._form = form
    End Sub

    Public Sub DisplayMessage()
        Dim label As New Form1.Label1ValueDelegate(AddressOf _form.Label1_Value)
        For i As Integer = 100 To 1 Step -1
            label.Invoke(i.ToString)
            System.Threading.Thread.Sleep(100)
        Next
    End Sub
End Class

何かヒントでも頂ければと考えます。
よろしくお願い致します。

引用返信 編集キー/
■45615 / inTopicNo.2)  Re[1]: 別スレッド動作中に親フォームを終了させるとエラー
□投稿者/ ほげ (1回)-(2010/01/15(Fri) 19:59:25)
2010/01/15(Fri) 20:00:29 編集(投稿者)
なぜわざわざ別クラス作成して複雑なコードを組んでいるのかがようわからん。
とりあえず、そのままの状態でやるとするなら

 Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As DoWorkEventArgs) Handles ackgroundWorker1.DoWork
        Dim bgw As BackgroundWorker = CType(sender, BackgroundWorker)
        Dim hoge As New hoge(Me)
        hoge.DisplayMessage(bgw, e)
 End Sub

Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
    Me.BackgroundWorker1.CancelAsync()
    While Me.BackgroundWorker1.IsBusy
        Application.DoEvents()
    End While
End Sub

' hogeクラス
Public Sub DisplayMessage(ByVal bgw As BackgroundWorker, ByVal e As DoWorkEventArgs)
    Dim label As New Form1.Label1ValueDelegate(AddressOf _form.Label1_Value)
    For i As Integer = 100 To 1 Step -1
        If bgw.CancellationPending Then
            e.Cancel = True
            Return
        End If
        label.Invoke(i.ToString)
        System.Threading.Thread.Sleep(100)
    Next
End Sub

とすればできる。


でもわざわざこんな複雑なコードを書かなくてもProgressChangeイベント関数はフォームスレッドで実行されるから
直接コントロールを扱えるから以下のコードで済む
(BackgroundWorkerのWorkeReportsProgress及びWorkerSupportsCancellationをTrueに設定しておく)

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    Dim bgw As BackgroundWorker = CType(sender, BackgroundWorker)
    For i As Integer = 100 To 1 Step -1
        If bgw.CancellationPending Then
            e.Cancel = True
            Return
        End If
        bgw.ReportProgress(i)
        System.Threading.Thread.Sleep(100)
    Next
End Sub

Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As System.Object, ByVal e ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
    Label1.Text = e.ProgressPercentage.ToString()
End Sub

引用返信 編集キー/
■45626 / inTopicNo.3)  Re[2]: 別スレッド動作中に親フォームを終了させるとエラ
□投稿者/ えれこぜ (2回)-(2010/01/16(Sat) 10:20:53)
2010/01/16(Sat) 16:08:33 編集(投稿者)
2010/01/16(Sat) 16:08:26 編集(投稿者)

ほげさん、返信ありがとうございました。

やはり今回のように強制的にフォームが閉じられる可能性がある場合、
1.FormClosingイベントで別スレッドをキャンセルさせる
2.さらに別スレッドがキャンセルされるまで待機
が必要なのですね。
今までは親フォームに全てのロジックを記述していたので、気づきませんでした。
又は、たまたま動いていただけかも知れません。
今から試してみようと思います。

> なぜわざわざ別クラス作成して複雑なコードを組んでいるのかがようわからん。
> でもわざわざこんな複雑なコードを書かなくてもProgressChangeイベント関数はフォームスレッドで実行されるから

UIとロジックを分けたいと考えていました。

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -