Операция 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