3

簡単に言えば、スレッドを使用しているときに、invoke やデリゲートを使用して別のクラスからユーザーフォームを更新する方法を理解しようとして、私はかなりの時間を費やしています。経験豊富な人にとっては、ばかげて明らかなことだと確信しています。おそらくデリゲートが必要であることはわかっていますが、私のすべての努力は、メインスレッドから呼び出されたときにのみ機能するようです。半日インターネットを見て回ったのですが、何かわからないことがあります。

例として、いくつかの疑似コードを次に示します。

このオプションは機能します:

Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim t1 As New Threading.Thread(AddressOf Count)

    t1.IsBackground = True

    t1.Start(100)
End Sub
Private Sub Count(ByVal Max As Object)
    If TypeOf Max Is Integer Then
        Count(CInt(Max))
    End If
End Sub


Private Sub SetLabelText(ByVal text As String)
    If Label1.InvokeRequired Then
        Label1.Invoke(New Action(Of String)(AddressOf SetLabelText), text)
    Else
        Label1.Text = text

    End If
End Sub

Private Sub Count(ByVal Max As Integer)
    For i = 1 To Max
        SetLabelText(CStr(i))
        Threading.Thread.Sleep(200)
    Next
End Sub
End Class

これ(わずかに異なるバリエーションの私の1000の努力の1つ)はそうではありません。実際には、この例では、サブルーチンの 1 つを独自のクラスに分離しようとしましたが、それ以外は、作成できるものと同じです。

Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim t1 As New Threading.Thread(AddressOf Count)
    t1.Start(100)

End Sub
Private Sub Count(ByVal Max As Object)
    If TypeOf Max Is Integer Then
        Dim class2 As New class2
        class2.Count(CInt(Max))
    End If
End Sub

Private Delegate Sub SetTextBoxTextInvoker(text As String)
Sub SetLabelText(ByVal text As String)
'or me.label1, form1.label1 or anything else I can try!
    If Me.InvokeRequired Then
        Me.Invoke(New SetTextBoxTextInvoker(AddressOf SetLabelText), _
               text)
    Else
        Me.Label1.Text = text
    End If
End Sub
End Class

Public Class class2
Sub Count(ByVal Max As Integer)
    For i = 1 To Max
        form1.SetLabelText(CStr(i))
        Threading.Thread.Sleep(200)
    Next
End Sub
End Class

私が知る限り、Sub "SetLabelText" 内の invokerequired の if ステートメントは決してトリガーされないようです。私の最善の推測は、invokerequired パラメータをチェックするときに、ユーザーフォームを正しく参照していないということですか? または、デリゲートに何か他のものを与える必要がありますか? 私は、間違っているかもしれない何百万もの小さな変数をいじることにイライラしています。事前にサポートを提供していただきありがとうございます。さらに情報が必要な場合はお知らせください。

4

2 に答える 2

2

まず、スレッドの代わりに Task Parallel Library を使用することをお勧めします。理解しやすく、操作しやすいです。例えば、

Dim countTask as New Task(Sub() Count(10))

Dim displayTask = countTask.ContinueWith(Sub()
                                           Me.Invoke(Sub() Label.Text = "10"

                                         End Sub)

 countTask.Start()

この例では、フォーム自体からこれを呼び出していることを前提としています。このメソッドを使用して、最初のタスクから 2 番目のタスクに値を返すことができます。より詳細な例が必要で、さらに多くの例が必要な場合は、http://msdn.microsoft.com/en-us/library/hh228603.aspxを確認してください。さらにサポートが必要な場合は、GitHub またはブログでいつでも何かを投げることができます。幸運を。

于 2013-09-10T23:51:01.943 に答える
2

あなたがやろうとしていることを理解しているかどうかはわかりませんが、コードに基づいて構築すると、次のコードを使用してラベルを安全に (「スレッドセーフに」) 設定できます。

Public Class Form1
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim t1 As New Threading.Thread(AddressOf Count)

        t1.IsBackground = True

        t1.Start(100)
    End Sub

    Private Sub Count(ByVal Max As Object)
        If TypeOf Max Is Integer Then
            Dim class2 As New Class2

            class2.Count(CInt(Max), AddressOf SetLabelText)
        End If
    End Sub

    Private Sub SetLabelText(ByVal text As String)
        If Label1.InvokeRequired Then
            Label1.Invoke(New SetText(AddressOf SetLabelText), text)
        Else
            Label1.Text = text
        End If
    End Sub
End Class

Public Class Class2
    Sub Count(ByVal Max As Integer, SetTextMethod As SetText)
        For i = 1 To Max
            SetTextMethod.Invoke((CStr(i)))

            Threading.Thread.Sleep(200)
        Next
    End Sub
End Class

Public Delegate Sub SetText(text As String)

「SetText」というデリゲートを作成しました。フォームがクラスで count 関数を呼び出すときに、SetLabelText メソッドを参照するデリゲートのインスタンスを渡すことができます。そのメソッド内で、ラベル テキストをデリゲートの新しいインスタンスと共に Invoke を介して直接または間接的に安全に設定できます。

絶対にやりたくないことは、クラスからフォームを参照することです(つまり、"form1.SetLabelText(CStr(i))"); プロジェクトの規模が大きくなり、要件が変化するにつれて、それは本当の悪夢を生み出す可能性があります!

あなたの質問を誤解したり、適切に答えなかったりした場合は、返信してください。

于 2013-09-10T23:23:14.780 に答える