- PR -

クラス内部でサブスレッドより非同期でイベントを発生させる方法

投稿者投稿内容
TASU
会議室デビュー日: 2006/08/04
投稿数: 7
投稿日時: 2006-08-04 20:06
サブスレッドよりイベントを発生させ、非同期でフォームを表示させたいのですが、うまいこと動きません。
何かよい方法をご存知の方いらっしゃいましたら、教えていただきたいです。
よろしくお願いします。

一応、デリゲートを定義しBeginInvokeメソッドを使ってsbCls_FormShowを呼んだりしてみましたが、やり方が悪かったのかうまくいきませんでした。
(BeginInvokeメソッドを使うと、sbCls_FormShowが新規スレッド上で呼ばれるからでしょうか?方法がわかりませんが、sbCls_FormShowをメインスレッド上で呼べばうまくいきますでしょうか。)


↓サンプルソースです↓
(下記モジュール、クラスの他に空のフォームを2つ作成し、Form1にDialogResultプロパティ='OK'のボタンを追加してください。)
コード:
Imports System.Threading
'==============================================================================
'==============================================================================
Module Main
    Sub main()
        Application.Run(New MainClass)
    End Sub
End Module 'Main
'==============================================================================
'==============================================================================
Public Class MainClass
    Inherits ApplicationContext

    Friend WithEvents sbCls As SubClass
    Friend WithEvents ntIcn As NotifyIcon
    Friend WithEvents ctMnu As ContextMenu

    Private IDX_END As Integer
    Private IDX_SND As Integer

    'サブスレッドより呼ばれるイベント
    Private Sub sbCls_FormShow(ByVal str As String) Handles sbCls.FormShow
        Dim f1 As New Form1

        'このイベントを非同期で発生させるか、もしくは非同期でForm1を表示させたい

        If f1.ShowDialog = DialogResult.OK Then
            Dim f2 As New Form2
            f2.Show()
        End If

    End Sub

    Private Sub Menu_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim ActMenu As MenuItem

        ActMenu = CType(sender, MenuItem)

        Select Case ActMenu.Index
            Case IDX_END
                sbCls.Dispose()
                ntIcn.Dispose()
                ExitThread()
            Case IDX_SND
                Dim f2 As New Form2
                f2.Show()

        End Select

    End Sub

    Public Sub New()

        Thread.CurrentThread.Name = "MainThread"

        'サブスレッドを開始するオブジェクト
        sbCls = New SubClass

        '----------------------------------'
        '-----------メニュー定義-----------'
        '----------------------------------'
        Dim tmpMenu As MenuItem

        ntIcn = New NotifyIcon
        With ntIcn
            .Icon = New System.Drawing.Icon("Icon1.ico")
            .Visible = True
            .Text = "MainClass"
        End With

        ctMnu = New ContextMenu

        tmpMenu = New MenuItem("終了(&E)", New System.EventHandler(AddressOf Me.Menu_Click))
        ctMnu.MenuItems.Add(tmpMenu)
        IDX_END = tmpMenu.Index

        tmpMenu = New MenuItem("表示(&V)", New System.EventHandler(AddressOf Me.Menu_Click))
        ctMnu.MenuItems.Add(tmpMenu)
        IDX_SND = tmpMenu.Index

        ntIcn.ContextMenu = ctMnu
        '----------------------------------'
        '----------------------------------'

    End Sub

End Class 'MainClass
'==============================================================================
'==============================================================================
Public Class SubClass
    Implements IDisposable

    Public Event FormShow(ByVal str As String)
    Private t As Thread

    'サブスレッド
    Sub FormShowThread()

        While True
            RaiseEvent FormShow("aiu")
            Thread.Sleep(10000)
        End While

    End Sub

    Public Sub New()

        'サブスレッドを開始する
        t = New Thread(AddressOf FormShowThread)
        With t
            .IsBackground = False
            .Name = "SubThread"
            .Start()
        End With

    End Sub

    Public Sub Dispose() Implements System.IDisposable.Dispose

        t.Abort()
        t.Join()

    End Sub
End Class 'SubClass


かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2006-08-04 20:53
で?一番大事な、サブスレッドの実装はどうなってんの?

そこんとこ見せてもらわないと、回答しようが無いんじゃないの?
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2006-08-04 21:04
何がしたいのか、どこが問題なのかがいまいちよくわかりません。

Form1を閉じると、すぐさまForm2が開き、その10秒後に再びForm1が開かれるようにしたいが、
なぜかForm2をクリックしても応答無しとなってしまうことが問題ということですか?

それとも、全く違う動作をさせたいのに上記のような意味不明な動作をしてしまうのが問題ですか?
TASU
会議室デビュー日: 2006/08/04
投稿数: 7
投稿日時: 2006-08-05 16:16
かずくんさん、けんじさん早速の返信有難うございます。問題点があまりにも不明確でしたね。申し訳ありません。

Thread.Sleep(10000)で実際にはUdpClientクラスのReceiveメソッドを使って受信待機させてます。データ受信時にForm1にデータ内容を表示させ、Form1を閉じるとForm2を表示させ返信できる処理、つまるところはメッセンジャーを作りたいです。(メッセンジャーが欲しい訳ではなくて、勉強のつもりでつくり始めました。)

が、けんじさんからの質問にもありましたとおり、Form2が動かなくなってしまいます。
自分の勉強不足ですが、原因がわかりません。

ちんぷんかんぷんな質問ばかりで申し訳ありませんが、お答えいただけると助かります。
よろしくお願いします。
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2006-08-05 18:25
Form2を呼び出す処理も更に別スレッドで行うようにしてください。
その際、Form2はShowDialogで呼び出してください。
TASU
会議室デビュー日: 2006/08/04
投稿数: 7
投稿日時: 2006-08-07 18:53
けんじさん返信有難うございます。

教えていただいた、
引用:

Form2を呼び出す処理も更に別スレッドで行うようにしてください。
その際、Form2はShowDialogで呼び出してください。


で、うまく動作しました。 ・・・が、

実は、Form2をインスタンス化するときに引数を渡しており、それを実現させるために、
引数を渡せるようにデリゲート宣言をし、BeginInvokeメソッドを使ってみました。
するとForm2のコマンドボタン押下時にフォルダブラウザを表示させているのですが、
それが正しく(枠のみでツリー部が)表示されません。

理由が全く解りません。ご存知の方いらっしゃいましたら、教えていただきたいです。
よろしくお願いします。

↓上記ソースのForm2をForm1とし、簡略化したサンプルです↓
Imports System.Threading
コード:
'==============================================================================
'==============================================================================
Module Main
    Sub main()
        Application.Run(New MainClass)
    End Sub
End Module 'Main
'==============================================================================
'==============================================================================
Public Class MainClass
    Inherits ApplicationContext

    Friend WithEvents ntIcn As NotifyIcon
    Friend WithEvents ctMnu As ContextMenu

    Public Delegate Sub Form1Delegate()

    Private IDX_END As Integer
    Private IDX_SND As Integer

    Private Sub RunForm1Thread()

        'デリゲート定義 - Form1でフォルダブラウザのフォルダツリーが
                          表示されない!
        Dim dlgt As Form1Delegate = New Form1Delegate(AddressOf Form1Thread)
        dlgt.BeginInvoke(Nothing, Nothing)

        'スレッド定義   - Form1でフォルダブラウザのフォルダツリーが
                          正しく表示される
        'Dim thrd As Thread = New Thread(AddressOf Form1Thread)
        'thrd.Start()

    End Sub

    Sub Form1Thread()
        Dim f1 As New Form1
        f1.ShowDialog()
    End Sub

    Private Sub Menu_Click(ByVal sender As Object, ByVal e As System.EventArgs)
        Dim ActMenu As MenuItem

        ActMenu = CType(sender, MenuItem)

        Select Case ActMenu.Index
            Case IDX_END
                ntIcn.Dispose()
                ExitThread()
            Case IDX_SND
                RunForm1Thread()
        End Select

    End Sub

    Public Sub New()

        '----------------------------------'
        '-----------メニュー定義-----------'
        '----------------------------------'
        Dim tmpMenu As MenuItem

        ntIcn = New NotifyIcon
        With ntIcn
            .Icon = New System.Drawing.Icon("Icon1.ico")
            .Visible = True
            .Text = "MainClass"
        End With

        ctMnu = New ContextMenu

        tmpMenu = New MenuItem("終了(&E)", New System.EventHandler(AddressOf Me.Menu_Click))
        ctMnu.MenuItems.Add(tmpMenu)
        IDX_END = tmpMenu.Index

        tmpMenu = New MenuItem("表示(&V)", New System.EventHandler(AddressOf Me.Menu_Click))
        ctMnu.MenuItems.Add(tmpMenu)
        IDX_SND = tmpMenu.Index

        ntIcn.ContextMenu = ctMnu
        '----------------------------------'
        '----------------------------------'

    End Sub

End Class 'MainClass
'==============================================================================
'==============================================================================

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Windows フォーム デザイナで生成されたコード "
        〜 中略 〜
#End Region

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim FolderBrowser As New FolderBrowserDialog

        If FolderBrowser.ShowDialog = DialogResult.OK Then
        End If

        FolderBrowser.Dispose()

    End Sub
End Class



TASU
会議室デビュー日: 2006/08/04
投稿数: 7
投稿日時: 2006-08-10 11:11
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

・・・いまだにわかりません。
どなたか解答してやってください。
お願いします。
Hongliang
ぬし
会議室デビュー日: 2004/12/25
投稿数: 576
投稿日時: 2006-08-10 12:10
スレッドアパートメントの問題でしょう。

……が、そもそもなぜ別スレッドでウィンドウを開けなければならないのか良く分からない……。
GUI スレッドは一つでいいと思うんですけどねー。

スキルアップ/キャリアアップ(JOB@IT)