跨线程操作无效... - VB.NET

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2240702/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 14:40:35  来源:igfitidea点击:

Crossthread operation not valid... - VB.NET

vb.netvisual-studio-2010multithreading

提问by lab12

I am using vb.net, and in my program I get this 'crossthread operation not valid' error when I run my backgroundworker that will make this textbox enabled true. My main sub will first turn the enabled to false, and when the backgroundworker runs it will turn it back true then exit. Why does it give me an error? FYI: There is more code to this but I don't want to make it any more confusing...

我正在使用 vb.net,并且在我的程序中,当我运行我的后台工作程序时,我会收到此“跨线程操作无效”错误,这将使此文本框启用为真。我的主要 sub 将首先将 enabled 变为 false,当后台工作程序运行时,它将返回 true 然后退出。为什么它给我一个错误?仅供参考:还有更多代码,但我不想让它变得更加混乱......

Here is the stack trace:

这是堆栈跟踪:

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)

and here is the exact error message:

这是确切的错误消息:

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

Can someone please help me out!

有人可以帮帮我吗!

Thanks,

谢谢,

KEvin

凯文

回答by Dan Tao

The purpose of the BackgroundWorkerclass is to perform work on a non-GUIthread while the GUI remains responsive. Unless you set Control.CheckForIllegalCrossThreadCallsto false(which you shouldn't do), or use Invokeas suggested in the other answers (which I also wouldn't recommend), you're going to get an illegal cross-thread operation exception.

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

If you want GUI-related "stuff" to happen whileyour BackgroundWorkeris running, I'd generally recommend using the BackgroundWorker.ReportProgressmethod and attaching an appropriate handler to the BackgroundWorker.ProgressChangedevent. If you want something on the GUI to happen once the BackgroundWorkeris finished, then simply attach your handler to update the GUI to the BackgroundWorker.RunWorkerCompletedevent.

如果你想GUI相关的“东西”的出现,而BackgroundWorker正在运行,我一般建议您使用BackgroundWorker.ReportProgress方法和安装合适的处理器的BackgroundWorker.ProgressChanged事件。如果你想在GUI上的东西,一旦发生BackgroundWorker完成,然后简单地附上您的处理程序来更新GUI的BackgroundWorker.RunWorkerCompleted事件。

回答by alex

Type the following code in the Form1_Load(or whatever your form is) sub:

Form1_Load(或任何您的表单)子中键入以下代码:

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False

It fixes all problems with blocked cross-thread operations.

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

回答by SSpoke

Better way to this in VB.NET is to use a Extensionit makes very nice looking code for cross-threading GUI Control Calls.

在 VB.NET 中更好的方法是使用Extension它为跨线程 GUI 控制调用制作非常漂亮的代码。

Just add this line of code to any Module you have.

只需将这行代码添加到您拥有的任何模块中即可。

<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

Now you can write Cross-Thread Control code that's only 1 line long for any control call.

现在您可以为任何控制调用编写只有 1 行长的跨线程控制代码。

Like this, lets say you want to clear a ComboBox and it's called from threads or without threads you can just use do this now

像这样,假设你想清除一个 ComboBox 并且它是从线程调用的,或者没有线程,你现在可以使用这样做

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

Want to add something after you clear it?

清除后要添加一些内容吗?

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

回答by Fredrik M?rk

Where exactly do you set the Enabledproperty? If you do it within the DoWorkevent handler, this code is running on a different thread than the button was created on, which should give the exception that you experience. To get around this, you should use BeginInvoke. For convenience it could be wrapped into a method, like so:

你究竟在哪里设置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

Now you can safely call that method to enable or disable any control from any thread:

现在您可以安全地调用该方法来启用或禁用来自任何线程的任何控制:

SetControlEnabled(someButton, False)

回答by jac

You cannot directly set a control's property that is on the UI thread from another thread. It can be done though, here is an example from msdn.

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

回答by AlperDiktas

Your Form_Load () pls write below code part. All your problems will be solved.

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

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

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False

回答by Venkat

Suggest to use AutomationPeer.

建议使用AutomationPeer。

For example below code calls Execute button when I press F5 key. Similarly if you want a thread or Background worker to call an event or function you can use Automation Peer. In your case instead of button (Which I used here) you can use text box with its appropriate property to invoke.

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

'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

Regards RV

问候房车

回答by CrazyCat Corporation

CheckForIllegalCrossThreadCalls = False