#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).