Crossthread操作无效… – VB.NET

我正在使用vb.net,并在我的程序中,当我运行我的backgroundworker将使此文本框启用true这个'crossthread操作无效'错误。 我的主要sub将首先把启用为false,当backgroundworker运行它将会把它变回真,然后退出。 为什么它给我一个错误? 供参考:有更多的代码,但我不想让它更混乱…

这是堆栈跟踪:

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."} 

有人可以帮我一把!

谢谢,

凯文

BackgroundWorker类的目的是在GUI保持响应的同时在非GUI线程上执行工作。 除非你设置Control.CheckForIllegalCrossThreadCallsfalse (你不应该这样做),或者按照其他答案(我也不build议这样)的build议使用Invoke ,否则你会得到非法的跨线程操作exception。

如果您希望 BackgroundWorker运行时发生与GUI相关的“内容”,我通常会推荐使用BackgroundWorker.ReportProgress方法,并将适当的处理程序附加到BackgroundWorker.ProgressChanged事件中。 如果您希望GUI中的某些内容在BackgroundWorker 完成后发生,那么只需附加您的处理程序即可将GUI更新为BackgroundWorker.RunWorkerCompleted事件。

你到底在哪里设置Enabled属性? 如果您在DoWork事件处理程序中执行该操作,则此代码在与创buildbutton不同的线程上运行,这应该会给您所遇到的exception。 为了解决这个问题,你应该使用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) 

Form1_Loadinput下面的代码(或者你的任何forms)sub:

 System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False 

它修复了被阻塞的跨线程操作的所有问题。

在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")) 

您不能直接从另一个线程设置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 

你的Form_Load()请写下面的代码部分。 你所有的问题都将解决。

 '## crossed-thread parts will not be controlled by this option... System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False 

build议使用AutomationPeer。

例如下面代码调用时按F5键执行button。 同样,如果您希望线程或后台工作者调用事件或函数,则可以使用自动化对等。 在你的情况下,而不是button(我在这里使用),你可以使用文本框及其适当的属性来调用。

 '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

 CheckForIllegalCrossThreadCalls = False