VB.NET Операция кросс-потоки недопустима, даже если используется Invoke! - PullRequest
1 голос
/ 28 сентября 2010

Я читал, пытаясь выяснить, почему я получаю это исключение безрезультатно.Я надеюсь, что кто-то видел это раньше:

Я использую Visual Basic 2010.

Вкратце, у меня есть форма «Панель настроек», создание которой занимает некоторое время (она содержит многометки и текстовые поля), поэтому я создаю его в другом потоке.

После загрузки его можно просмотреть, нажав кнопку, которая изменяет видимость формы на True.Я использую следующую подпрограмму для обработки вызовов для своих элементов управления:

Public Sub InvokeControl(Of T As Control)(ByVal Control As T, ByVal Action As Action(Of T))
        If Control.InvokeRequired Then
            Control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl), New Object() {Control, Action})
        Else
            Action(Control)
        End If
End Sub

Вот соответствующая часть моего основного кода (SettingsTable наследует TableLayoutPanel, а HelperForm наследует Form):

Public Class ch4cp
Public RecipeTable As SettingsTable
Public WithEvents SettingsWindow As HelperForm

Private Sub ch4cp_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

PanelCreatorThread = New Threading.Thread(AddressOf CreateStartupPanels)
        PanelCreatorThread.Start()

End Sub

 Private Sub CreateStartupPanels()

        SettingsWindow = New HelperForm("Settings Panel")
        SettingsTable = New SettingsTable

            SettingsTable.Create()
            SettingsWindow.Controls.Add(SettingsTable)

End Sub

Private Sub ViewSettingsPanel_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ViewSettingsPanel.CheckedChanged

InvokeControl(SettingsWindow, Sub(x) x.Visible = ViewSettingsPanel.Checked)

End Sub

SettingsTableМетод .Create () генерирует набор меток и текстовых ящиков на основе содержимого настроек приложения и добавляет их в таблицу параметров.

Когда я нажимаю флажок ViewSettingsPanel, я получаю ошибку нарушения межпотокового режима.Есть идеи?Я был бы очень признателен.

Ответы [ 2 ]

1 голос
/ 28 сентября 2010

Я понял это.В случае, если кто-то еще может столкнуться с подобной проблемой, вот секрет:

В классе SettingsTable у меня есть метод MakeTable, который выглядит следующим образом:

Private Sub MakeTable()
        Me.Visible = False
        Me.Controls.Clear()
        ... add some controls ...
        Me.Visible = True
End Sub

Я сделал эточтобы элемент управления не мерцал, если таблица была переделана, пока она видна.Я не совсем понимаю, почему (из чтения я предполагаю, что это что-то вроде дескрипторов для дочерних элементов управления не было создано, потому что они не были показаны после создания, поэтому IsInvokeRequired оценивается как False, когда должно было быть True).Исправление было сделано следующим образом:

Private Sub MakeTable()
        If Not IsNothing(Me.Parent) Then If Me.Parent.Visible Then Me.Visible = False
        Me.Controls.Clear()
        ... add some controls ...
        Me.Visible = True
End Sub

Таким образом, дочерние элементы управления «отображаются» в невидимой форме SettingsWindow, и поэтому создаются их дескрипторы.Работает просто отлично сейчас!

0 голосов
/ 17 мая 2014

Лучшим способом для этого в 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-код длиной всего одной строки для любого управляющего вызова.

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

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

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

cboServerList.Invoke(Sub() cboServerList.Items.Add("Hello World"))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...