Недопустимая операция с перекрестным потоком

#vb.net

#vb.net

Вопрос:

Я делал следующее, чтобы опробовать потоки, но получил ошибку ‘Cross-Threading’ в строке txtBox.Text = DataGridView2.Rows.Item(iloop).Cells(3).Value , любой может указать, что не так, спасибо:

 Dim lm As New Thread(AddressOf load_movie)
        Dim lt As New Thread(AddressOf load_timings)
        lm.Start()
        lt.Start()

Private Sub load_movie()

        For iloop As Integer = 0 To DataGridView1.Rows.Count - 2
            Dim Cstring As String = "txt_Movie_0" amp; iloop.ToString
            For Each cCtrl As Control In Panel1.Controls
                If TypeOf cCtrl Is TextBox Then
                    Dim txtBox As TextBox
                    txtBox = cCtrl
                    If txtBox.Name = Cstring Then
                        txtBox.Text = DataGridView1.Rows.Item(iloop).Cells(1).Value
                    End If
                End If
            Next
        Next
    End Sub

    Private Sub load_timings()
        For iloop As Integer = 0 To DataGridView2.Rows.Count - 2
            For Each cCtrl As Control In Panel2.Controls
                If TypeOf cCtrl Is TextBox Then
                    Dim txtBox As TextBox
                    txtBox = cCtrl
                    If (txtBox.Name.Substring(9, 6)) = (DataGridView2.Rows.Item(iloop).Cells(0).Value.substring(0, 6)) Then
                        txtBox.Text = DataGridView2.Rows.Item(iloop).Cells(3).Value 'This is the part that says "Cross-thread operation not valid: Control 'txt_Time_00_000' accessed from a thread other than the thread it was created on."
                    End If
                End If
            Next
        Next

    End Sub
  

Ответ №1:

Доступ к элементу пользовательского интерфейса из чего-либо другого, кроме потока пользовательского интерфейса, не является законным .Сетевой код. Следовательно, когда вы пытаетесь использовать DataGridView2 экземпляр из фонового потока, он по праву выдает исключение.

Для чтения или записи в компонент пользовательского интерфейса вам необходимо использовать метод Invoke or BeginInvoke , чтобы вернуться в поток пользовательского интерфейса и выполнить обновление. Например

 If TypeOf cCtrl Is TextBox Then
    Dim txtBox As TextBox
    txtBox = cCtrl
    txtBox.Invoke(AddressOf UpdateTextBox, txtBox, iloop)
End If

Private Sub UpdateTextBox(txtBox as TextBox, iloop as Integer) 
    If (txtBox.Name.Substring(9, 6)) = (DataGridView2.Rows.Item(iloop).Cells(0).Value.substring(0, 6)) Then
        txtBox.Text = DataGridView2.Rows.Item(iloop).Cells(3).Value 'This is the part that says "Cross-thread operation not valid: Control 'txt_Time_00_000' accessed from a thread other than the thread it was created on."
    End If
End Sub
  

Ответ №2:

@JaredPar у вас есть основная идея, но сам этот код не будет компилироваться (если только я чего-то не упустил). Для VB9 или менее вам нужно объявить фактический делегат и вызвать его:

     ''//The delegate is only needed for the VB 9 or less version
    Private Delegate Sub UpdateTextBoxDelegate(ByVal txtBox As TextBox, ByVal value As String)

    If TypeOf cCtrl Is TextBox Then
        Dim txtBox As TextBox
        txtBox = cCtrl
        ''//Perform validation logic here
        If (txtBox.Name.Substring(9, 6)) = (DataGridView2.Rows.Item(iloop).Cells(0).Value.ToString().Substring(0, 6)) Then
            ''//Call the update method with our textbox and value
            UpdateTextBox(txtBox, DataGridView2.Rows.Item(iloop).Cells(3).Value.ToString())
        End If
    End If

    Private Sub UpdateTextBox(ByVal txtBox As TextBox, ByVal value As String)
        ''//Basically ask the textbox if we need to invoke
        If txtBox.InvokeRequired Then
            ''//For VB 9 or less you need a delegate
            txtBox.Invoke(New UpdateTextBoxDelegate(AddressOf UpdateTextBox), txtBox, value)
        Else
            txtBox.Text = value
        End If
    End Sub
  

Для VB 10 мы, наконец, можем использовать анонимные подменю, чтобы полностью избавиться от делегата:

     If TypeOf cCtrl Is TextBox Then
        Dim txtBox As TextBox
        txtBox = cCtrl
        ''//Perform validation logic here
        If (txtBox.Name.Substring(9, 6)) = (DataGridView2.Rows.Item(iloop).Cells(0).Value.ToString().Substring(0, 6)) Then
            ''//Call the update method with our textbox and value
            UpdateTextBox(txtBox, DataGridView2.Rows.Item(iloop).Cells(3).Value.ToString())
        End If
    End If

Private Sub UpdateTextBox(ByVal txtBox As TextBox, ByVal value As String)
    If txtBox.InvokeRequired Then
        ''//For VB 10 you can use an anonymous sub
        txtBox.Invoke(Sub() UpdateTextBox(txtBox, value))
    Else
        txtBox.Text = value
    End If
End Sub