none
スレッド内で表示させたフォームを操作できるようにしたい RRS feed

  • 質問

  • Public Class frmMain
        Private _noticeMonitorThread As Thread
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            Try
                _startNotifyMonitorThread()
            Catch ex As Exception
                MessageBox.Show(ex.Message, Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Stop)
                Application.Exit()
            End Try
        End Sub
    
        Private Sub _startNotifyMonitorThread()
            ' 監視開始
            _noticeMonitorThread = New Thread(New ThreadStart(AddressOf _noticeMonitorTask))
            _noticeMonitorThread.IsBackground = True
            _noticeMonitorThread.Start()
        End Sub
        
        Private Sub _noticeMonitorTask()
            Do While True
                Dim monitor As New NoticeMonitor()
                monitor.Monitoring()
    
                Thread.Sleep(1000)
            Loop
        End Sub
    End Class
    
    Friend Class NoticeMonitor
        Public Sub Monitoring()
            Dim form As New frmHoge()
            form.Show()
        End Sub
    End Class

    上記コードで、Threadの中でフォームを表示させ、そのフォームをクリックさせたいのですが、
    画像のように、Windowsに制御が戻ってこない為、フォームをクリックすることができません。
    Application.DoEvents()を走行させてもダメでした。



    いわゆる更新通知をウィンドウ右下に表示させて、クリックすると画面を表示する、ということが
    したいのですが、どのようにコードすればフォームをクリックすることが出来るようになるのでしょうか?

    2013年8月16日 4:21

回答

  • Windows において、フォーム(ウィンドウ)はそれを作ったスレッドに属するので、そのスレッドでメッセージループ(ボタンが押されたなどのイベントを処理する仕組み)が動かないと、操作を受け付けることができません。
    次に、ワーカースレッド(処理をするために自分で作った Thread、BackgroundWorker、Task など)でフォーム(ウィンドウ)を表示することはあまりよくありません。

    持って行くべき方向性としては、以下のことが考えられます。

    • フォームはメインスレッド(Button1_Click などが動くスレッド)で表示する。
    • 新着のお知らせを監視する(ポーリングする)処理を Thread で実行する。
    • 新着を確認したときは Invoke メソッドなどを使ってメインスレッド側に表示処理を通知する。

    参考:DOBON.NET さんの記事

    • 回答としてマーク takiru 2013年8月16日 6:08
    2013年8月16日 5:29
    モデレータ

すべての返信

  • Windows において、フォーム(ウィンドウ)はそれを作ったスレッドに属するので、そのスレッドでメッセージループ(ボタンが押されたなどのイベントを処理する仕組み)が動かないと、操作を受け付けることができません。
    次に、ワーカースレッド(処理をするために自分で作った Thread、BackgroundWorker、Task など)でフォーム(ウィンドウ)を表示することはあまりよくありません。

    持って行くべき方向性としては、以下のことが考えられます。

    • フォームはメインスレッド(Button1_Click などが動くスレッド)で表示する。
    • 新着のお知らせを監視する(ポーリングする)処理を Thread で実行する。
    • 新着を確認したときは Invoke メソッドなどを使ってメインスレッド側に表示処理を通知する。

    参考:DOBON.NET さんの記事

    • 回答としてマーク takiru 2013年8月16日 6:08
    2013年8月16日 5:29
    モデレータ
  • ご回答ありがとうございます。

    私も調べていたところ、Invoke()でコントロールの操作を行うようなことを見つけました。
    Application.Run()でどうにかならないか試していましたが、セオリー的にはInvoke()で
    するものなのですね。

    状態監視をスレッドで行うというのには確かに、と納得です。
    メッセージループは1つのまま、別スレッドにすべき点とそうでなくて構わない点を
    切り分けて処理すべきということですね。

    状態監視のみをスレッドで行い、Invoke()で処理させたところ、上手く動作させることが
    できました。
    ありがとうございます。

    2013年8月16日 6:07