перекрестный класс перекрестного чтения vb.net проблема

#vb.net #multithreading #function

#vb.net #многопоточность #функция

Вопрос:

у меня есть мой класс form и второй модуль с некоторыми специальными функциями, когда я нажимаю кнопку в своей форме, я запускаю общедоступную функцию из второго модуля (которая позже запускает другие общедоступные функции из второго модуля) в отдельном потоке, я устанавливаю SetApartmentState(ApartmentState.STA), и япробовал использовать deletage sub и CheckForIllegalCrossThreadCalls = False, но проблема остается прежней, мои потоковые функции (которые находятся во втором модуле) не могут получить доступ к моим элементам управления формами, но когда я перемещаю функции в класс form, все снова работает, что вы предлагаете для решения этой проблемы?

 Public Class Form1
Dim T0 As Thread

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    CheckForIllegalCrossThreadCalls = False
End Sub

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    T0 = New Thread(AddressOf sub1)
    T0.SetApartmentState(ApartmentState.STA)
    T0.start()
End Sub
End Class


Module Module1

Public Sub Sub1()
msgbox(form1.textbox1.text)    'even if the textbox contains content it returns ""    
Function2()
End Sub

Public Function Function1()
'SomeInstructions
msgbox(form1.textbox1.text)    'same problem here
End Function

End module
  

PS: это не выдает никаких ошибок или не останавливает код во время отладки, и я попытался поместить sub1 в класс form и другие функции в модуле, но тогда только он sub1 может получить доступ к элементам управления, я попробовал делегировать, но я не знаю, правильно ли я это сделал,кто-нибудь может внести какие-либо предложения, пожалуйста

Комментарии:

1. Пожалуйста, включите минимальный пример, который продемонстрировал бы описанное поведение. Я не сомневаюсь, что решение тривиально, но, не видя некоторого кода, трудно сказать, в чем проблема.

2. Я просто сделал, если кто-нибудь может подсказать, как это решить, пожалуйста

Ответ №1:

Здесь есть две проблемы.

Одна из них связана с тем, как формы по умолчанию работают в VB.NET . Видите ли, в C # вам нужен конкретный экземпляр type Form1 для доступа к его нестатическим элементам, тогда как в VB.NET Form1 выглядит как экземпляр формы , позволяющий вам писать такие вещи, как Form1.TextBox1.Text . Это отлично работает, пока вы обращаетесь к членам Form1 из потока пользовательского интерфейса, но когда вы пытаетесь получить его из фонового потока, создается новый экземпляр Form1 , и Form1.TextBox1 этот поток фактически указывает на совершенно другой экземпляр TextBox .

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

Способ обойти это — сохранить конкретную ссылку Form1 , чтобы вы могли передавать ее.

Когда вы переходите

 Dim myForm As New Form1
  

… или

 Dim myForm As Form1 = Me
  

… переменная ‘myForm’, указывающая на этот конкретный Form1 экземпляр, может затем передаваться между потоками, как и любая другая ссылка, и не изменит ее значение.

Это, однако, подводит нас к проблеме # 2:

Вы не должны обращаться к элементу управления пользовательского интерфейса (что означает любой тип, производный от Control потока, который включает Form в себя поток, отличный от потока, в котором он был создан.

Если вам абсолютно необходимо, вы должны маршалировать вызовы, обращающиеся Control к потоку, в котором он был создан, например, с помощью Invoke / BeginInvoke (есть и другие способы).

Вот модификация вашего кода для достижения желаемого, а также более сложный пример, демонстрирующий «переключение» нескольких потоков: сбор интересного состояния в потоке пользовательского интерфейса, выполнение работы с ним в фоновом потоке, затем отображение результатов в потоке пользовательского интерфейса.

 Imports System.Threading

Public Class Form1

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ' We don't need this anymore.
    ' We'll do things right and access
    ' the UI on the UI thread only.
    ' CheckForIllegalCrossThreadCalls = False
  End Sub

  Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    ' Note that we're passing a reference
    ' to THIS instance of Form1 to Sub1 and Sub2.
    Dim form As Form1 = Me

    ' Let's spin up some threads.
    Dim T0 As New Thread(Sub() Module1.Sub1(form))

    T0.Start()

    Dim T1 As New Thread(Sub() Module1.Sub2(form))

    T1.Start()
  End Sub

End Class

Module Module1

  ' Note that this sub now accepts
  ' a reference to an instance of Form1.
  Public Sub Sub1(form As Form1)
    ' This is what we want to do:
    Dim action As New Action(Sub() MsgBox(form.TextBox1.Text))

    ' See if we're on the right thread.
    If form.InvokeRequired Then
      ' Invoke on the thread which created this Form1 instance.
      form.Invoke(action)
    Else
      ' Invoke on the current thread.
      action.Invoke()
    End If
  End Sub

  ' This is a more complex example.
  Public Sub Sub2(form As Form1)
    ' This function will get the text from TextBox1 when invoked.
    ' It still needs to be invoked on the UI thread though.
    Dim getText As New Func(Of String)(Function() form.TextBox1.Text)

    Dim text As String

    If form.InvokeRequired Then
      text = CStr(form.Invoke(getText))
    Else
      text = getText() ' Shorthand syntax.
    End If

    ' Now that we have the text, let's do some
    ' intensive work with it while we're on
    ' the background thread.
    For i = 0 To 5
      text amp;= i

      Thread.Sleep(100)
    Next

    ' Now we want to show the message box - again, on the UI thread.
    Dim showMessageBox As New Action(Sub() MsgBox(text))

    If form.InvokeRequired Then
      form.Invoke(showMessageBox)
    Else
      showMessageBox()
    End If
  End Sub

End Module
  

Комментарии:

1. Спасибо, поскольку я довольно новичок в vb.net я не получил код, который вы написали, но использование переменной формы было полезным

2. @user3781458, если приведенный выше код выглядит для вас как тарабарщина, это потому, что а) он основан на низкоуровневых конструкциях тех дней, когда асинхронное программирование было формой искусства; в современных VB.NET , а именно Task и Async / Await; и б) это требует понимания делегатови замыкания , что необходимо для написания качественного асинхронного кода (и полезно для работы с некоторыми другими технологиями, такими как LINQ).