web-dev-qa-db-ja.com

クロススレッド操作が無効です...-VB.NET

私はvb.netを使用しています。私のプログラムでは、このテキストボックスを有効にするバックグラウンドワーカーを実行すると、この「クロススレッド操作が無効です」というエラーが表示されます。私のメインサブは最初に有効をfalseに変更し、バックグラウンドワーカーが実行するとtrueに戻して終了します。エラーが発生するのはなぜですか?参考:これにはもっと多くのコードがありますが、これ以上混乱させたくありません...

スタックトレースは次のとおりです。

at System.Windows.Forms.Control.get_Handle()
   at System.Windows.Forms.Control.OnEnabledChanged(EventArgs e)
   at System.Windows.Forms.Control.set_Enabled(Boolean value)
   at Helium.Form1.BackgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in C:\Users\Kevin\documents\visual studio 2010\Projects\Helium\Helium\Form1.vb:line 167
   at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
   at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)

そしてここに正確なエラーメッセージがあります:

{"Cross-thread operation not valid: Control 'mainText' accessed from a thread other than the thread it was created on."}

誰かが私を助けてくれますか?

おかげで、

ケビン

13
lab12

BackgroundWorkerクラスの目的は、GUIの応答性を維持しながらnon-GUIスレッドで作業を実行することです。 Control.CheckForIllegalCrossThreadCallsfalseに設定しない限り(これは推奨されません)、または他の回答で提案されているようにInvokeを使用しない限り(推奨しません)、次のようになります。不正なスレッド間操作例外。

GUI関連の「もの」を発生させたい場合whileBackgroundWorkerが実行されている場合、通常、BackgroundWorker.ReportProgressメソッドを使用し、BackgroundWorker.ProgressChangedイベントに適切なハンドラーをアタッチすることをお勧めします。 BackgroundWorkerfinishedになったときにGUIで何かを実行したい場合は、ハンドラーをアタッチしてGUIをBackgroundWorker.RunWorkerCompletedイベントに更新します。

22
Dan Tao

Form1_Load(またはフォームが何であれ)サブに次のコードを入力します。

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False

ブロックされたクロススレッド操作に関するすべての問題を修正します。

13
alex

VB.NETでこれを行うためのより良い方法は、Extensionを使用することです。これにより、クロススレッドのGUIコントロール呼び出し用の見栄えの良いコードが作成されます。

このコード行を任意のモジュールに追加するだけです。

<System.Runtime.CompilerServices.Extension()> _
Public Sub Invoke(ByVal control As Control, ByVal action As Action)
    If control.InvokeRequired Then
        control.Invoke(New MethodInvoker(Sub() action()), Nothing)
    Else
        action.Invoke()
    End If
End Sub

これで、任意の制御呼び出しに対して1行のみのクロススレッド制御コードを記述できます。

このように、ComboBoxをクリアし、スレッドから呼び出されるか、スレッドなしで使用できるとしましょう。

cboServerList.Invoke(Sub() cboServerList.Items.Clear())

クリアした後に何か追加したいですか?

cboServerList.Invoke(Sub() cboServerList.Items.Add("Hello World"))
12
SSpoke

Enabledプロパティを正確にどこに設定しますか? DoWorkイベントハンドラー内で実行すると、このコードは、ボタンが作成されたスレッドとは別のスレッドで実行されているため、例外が発生します。これを回避するには、BeginInvokeを使用する必要があります。便宜上、次のようにメソッドにラップできます。

Private Sub SetControlEnabled(ByVal ctl As Control, ByVal enabled As Boolean)
    If ctl.InvokeRequired Then
        ctl.BeginInvoke(New Action(Of Control, Boolean)(AddressOf SetControlEnabled), ctl, enabled)
    Else
        ctl.Enabled = enabled
    End If
End Sub

これで、そのメソッドを安全に呼び出して、任意のスレッドから任意のコントロールを有効または無効にすることができます。

SetControlEnabled(someButton, False)
11
Fredrik Mörk

UIスレッド上にあるコントロールのプロパティを別のスレッドから直接設定することはできません。ただし、これはmsdnの例です。

Private Sub SetText(ByVal [text] As String)

    ' InvokeRequired required compares the thread ID of the'
    ' calling thread to the thread ID of the creating thread.'
    ' If these threads are different, it returns true.'
    If Me.textBox1.InvokeRequired Then
        Dim d As New SetTextCallback(AddressOf SetText)
        Me.Invoke(d, New Object() {[text]})
    Else
        Me.textBox1.Text = [text]
    End If
End Sub
2
jac

Form_Load()plsは、コード部分の下に記述します。すべての問題が解決されます。

'## crossed-thread parts will not be controlled by this option...

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False
1
AlperDiktas

AutomationPeerの使用を提案します。

以下の例では、F5キーを押すと、実行ボタンが呼び出されます。同様に、スレッドまたはバックグラウンドワーカーでイベントまたは関数を呼び出す場合は、オートメーションピアを使用できます。ボタンの代わりに(ここで使用したもの)、適切なプロパティを持つテキストボックスを使用して呼び出すことができます。

'Button name=btnExecute

'Imports System.Windows.Automation.Peers

'Imports System.Windows.Automation.Provider

If e.Key = Key.F5 Then

   Dim peer As New ButtonAutomationPeer(btnExecute)

   Dim invokeProv As IInvokeProvider = TryCast(peer.GetPattern(PatternInterface.Invoke), IInvokeProvider)

   invokeProv.Invoke()

End If

よろしくRV

0
Venkat