Операция Crossthread не действительна... - VB.NET

Я использую vb.net, и в моей программе я получаю эту ошибку "crossthread operation not valid" при запуске моего фонового рабочего, который сделает это текстовое поле включенным. Мой главный юг сначала включит значение false, а когда работает фоновой рабочий стол, он вернет true, а затем выйдет. Почему это дает мне ошибку? FYI: для этого есть больше кода, но я не хочу больше запутывать его...

Вот трассировка стека:

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

Кто-нибудь может помочь мне!

Спасибо,

Кевин

Ответ 1

Цель класса BackgroundWorker - выполнить работу над потоком non-GUI, в то время как графический интерфейс остается отзывчивым. Если вы не установили Control.CheckForIllegalCrossThreadCalls в false (который вы не должны делать) или используйте Invoke, как указано в других ответах (которые я также не рекомендую), вы получите незаконный кросс- исключение операции потока.

Если вы хотите, чтобы "материал", связанный с GUI, был , а выполнялся ваш BackgroundWorker, я бы рекомендовал использовать метод BackgroundWorker.ReportProgress и привязать соответствующий обработчик к BackgroundWorker.ProgressChanged мероприятие. Если вы хотите, чтобы что-то в графическом интерфейсе произошло после завершения BackgroundWorker , просто добавьте обработчик для обновления GUI к событию BackgroundWorker.RunWorkerCompleted.

Ответ 2

Где именно вы устанавливаете свойство 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)

Ответ 3

Введите следующий код в Form1_Load (или независимо от вашей формы):

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False

Он устраняет все проблемы с заблокированными операциями с поперечными потоками.

Ответ 4

В VB.NET лучше всего использовать Extension, он делает очень приятный код для кросс-потоковых вызовов управления графическим интерфейсом.

Просто добавьте эту строку кода в любой имеющийся у вас модуль.

<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

Теперь вы можете написать Cross-Thread Control код, который имеет только 1 строку для любого вызова управления.

Как это, скажем, вы хотите очистить ComboBox, и он вызван из потоков или без потоков, которые вы можете использовать только сейчас.

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

Хотите добавить что-то после его очистки?

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

Ответ 5

Вы не можете напрямую установить свойство управления, которое находится в потоке пользовательского интерфейса из другого потока. Это можно сделать, но вот пример из 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

Ответ 6

Ваши Form_Load() PLS пишут ниже часть кода. Все ваши проблемы будут решены.

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

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False

Ответ 7

Предложите использовать 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

Ответ 8

CheckForIllegalCrossThreadCalls = False