none
別クラスからformクラスへのinvoke方法 RRS feed

  • 質問

  • vb2005を勉強中の初心者です。

    別スレッドから、リストボックスにメッセージを表示する簡単なプログラムを作成中なのですが、

    FORMクラスからのINVOKEは正常にメッセージが表示されますが、別クラスからのinvokeは

    ”ウィンドウ ハンドルが作成される前、コントロールで Invoke または BeginInvoke を呼び出せません。”

    のエラーになります。

    色々試してみましたがうまくいきません。

    ご教授よろしくお願いいたします。

    os windowsxp

     

    Public Class Form1
        Delegate Sub delmyprint(ByVal str As String)

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            '別スレッドで開始する
            Dim myThread As Thread
            myThread = New Thread(New ThreadStart(AddressOf session1))
            myThread.IsBackground = True
            myThread.Start()
            Control.CheckForIllegalCrossThreadCalls = False
        End Sub
        Private Sub session1()
            Dim dlg As New delmyprint(AddressOf MyPrint)
            logbox.Invoke(dlg, New Object() {"session1"})
            Dim myThread1 As Thread
            myThread1 = New Thread(New ThreadStart(AddressOf session2))
            myThread1.IsBackground = True
            myThread1.Start()
            Control.CheckForIllegalCrossThreadCalls = False
        End Sub
        Private Sub session2()
            Dim dlg As New delmyprint(AddressOf MyPrint)
            logbox.Invoke(dlg, New Object() {"session2"})
            Dim cls_test1 As New test1
            cls_test1.st1()


        End Sub
        'ログウィンドウに1行表示
        Sub MyPrint(ByVal str As String)
            'SyncLock logBox
            If Me.logbox.InvokeRequired Then
                Dim dlg As New delmyprint(AddressOf MyPrint)
                Me.Invoke(dlg, New Object(), str)
            End If
            logbox.Items.Add(str)
            logbox.TopIndex = logbox.Items.Count - 1
            logbox.Refresh()
            'End SyncLock
        End Sub
    End Class
    Public Class test1
        Inherits Form1

        Public Sub st1()

            Dim dlg As New delmyprint(AddressOf Form1.MyPrint)
            logbox.Invoke(dlg, New Object() {"session3"}) <--- ここでエラーになります
        End Sub
    End Class

    2007年7月29日 9:31

すべての返信

  •  初心者 さんからの引用

        Sub MyPrint(ByVal str As String)
            If Me.logbox.InvokeRequired Then
                Dim dlg As New delmyprint(AddressOf MyPrint)
                Me.Invoke(dlg, New Object(), str)
            End If
        End Sub

    MyPrintをInvokeする必要があるか判断して、Invokeするか直接呼び出すかは呼び出し側の仕事です。

    Session1()、Session2()で判断することになります。

    #スレッドからスレッドを起動しているのはわけがあるのでしょうか?

     

     初心者 さんからの引用

    Public Class test1
        Inherits Form1

        Public Sub st1()

            Dim dlg As New delmyprint(AddressOf Form1.MyPrint)
            logbox.Invoke(dlg, New Object() {"session3"}) <--- ここでエラーになります
        End Sub
    End Class

    「Form1.MyPrint」と書かれています。

    Form1は型です。インスタンスではありません。

    エラーにならない理由は下記のヘルプを見てください。>VB2005の機能です。

    「暗黙のフォームインスタンス」

    http://msdn2.microsoft.com/ja-jp/library/1fsza1t2(VS.80).aspx

     

    つまり、Form1の新しいインスタンスが裏で作成されています。

    それはNew Form1のみの状態です。

    したがってエラーにあるウィンドウハンドルなどのリソースがまだ作成されていない状態です。

    その状態でいきなりMyPrintが実行されるため発生しています。

    あえて正すならMe.MyPrintということになります。

    しかし、

    Dim testclass As New test1

    testclass.st1()

    とすれば同じエラーになると思われます。>logbox.って書いてるからその時点でハンドルができて動くかも。

    理由は一緒です。

    2007年7月30日 4:52
  • まどかさん 回答ありがとうございます。

     

    スレッドからスレッドを呼び出しているのは、単なるテストのために作っただけです。

    ご指摘によれば、私のプログラムでのinvokeの使用は間違っていると理解しました。

    適切な他クラスからのform制御のサンプルがあれば紹介していただけないでしょうか。

    よろしくお願いいたします。

    2007年7月30日 5:36
  • 新規プロジェクトでButtonとProgressBarを貼り付け適当な大きさにしてください。

    あとは下記を丸々貼り付けてください。

    InvokeRequiredを判断しているタイミングとInvokeが必要な処理が分離されているところが違いです。

     

    Imports System.Threading
    Public Class Form1
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            With ProgressBar1
                .Minimum = 0
                .Maximum = 100
                .Value = 0
            End With
            Dim newThreadClass1 As New ThreadClass1(Me.ProgressBar1)
            Dim newThread As New Thread(AddressOf newThreadClass1.ThreadProc)
            newThread.Start()
        End Sub

        Private Class ThreadClass1
            Private _ProgressBar As ProgressBar
            Public Sub ThreadProc()
                Dim dlg As New dlgSetProgressBarValue(AddressOf SetProgressBarValue)
                For value As Integer = 0 To 100 Step 10
                    If _ProgressBar.InvokeRequired Then
                        _ProgressBar.Invoke(dlg, New Object() {value})
                    Else
                        SetProgressBarValue(value)
                    End If
                    Thread.Sleep(1000)
                Next
            End Sub
            Private Delegate Sub dlgSetProgressBarValue(ByVal value As Integer)
            Private Sub SetProgressBarValue(ByVal value As Integer)
                _ProgressBar.Value = value
            End Sub
            Public Sub New(ByVal targetProgressBar As ProgressBar)
                _ProgressBar = targetProgressBar
            End Sub
        End Class
    End Class

    2007年7月30日 7:26
  • まどかさん サンプルありがとうございます。

    じっくりと勉強させていただきます。

    又質問させていただくかもしれません。

    よろしくお願いいたします。

    2007年7月30日 8:19