交叉线程跨类vb.net问题
我有我的表单类,还有第二个模块,有一些特殊的函数, 当我单击表单上的一个按钮时,我在一个单独的线程中运行第二个模块中的一个公共函数(稍后从第二个模块中运行其他公共函数),我设置了SetApartmentState(ApartmentState.STA),并尝试使用deltage sub和CheckForIllegalCrossThreadCalls=False,但问题仍然是我的线程函数(位于第二个模块上)无法访问我的表单控件,但是当我将函数移动到表单类时,所有功能都会再次工作,您建议如何解决此问题交叉线程跨类vb.net问题,vb.net,multithreading,function,Vb.net,Multithreading,Function,我有我的表单类,还有第二个模块,有一些特殊的函数, 当我单击表单上的一个按钮时,我在一个单独的线程中运行第二个模块中的一个公共函数(稍后从第二个模块中运行其他公共函数),我设置了SetApartmentState(ApartmentState.STA),并尝试使用deltage sub和CheckForIllegalCrossThreadCalls=False,但问题仍然是我的线程函数(位于第二个模块上)无法访问我的表单控件,但是当我将函数移动到表单类时,所有功能都会再次工作,您建议如何解决此问
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可以访问控件,我尝试了委托,但我不知道我是否做对了,有人能提些建议吗 其中一个原因是VB.NET中默认表单的工作方式。请参见,在C中,您需要一个具体的
Form1
类型的实例来访问其非静态成员,而在VB.NET中Form1
看起来像是表单的一个实例,允许您编写Form1.TextBox1.Text
之类的内容。当您访问正在从UI线程中删除Form1
的成员,但当您尝试从后台线程获取它时,将创建Form1
的新实例,并且该线程看到的Form1.TextBox1
实际上指向了一个完全不同的TextBox
实例
另一种说法是VB.NET中的默认表单实例是线程静态的
解决这个问题的一种方法是保留对Form1
的具体引用,以便您可以传递它
你什么时候走
Dim myForm As New Form1
…或
Dim myForm As Form1 = Me
…指向特定Form1
实例的“myForm”变量可以像任何其他引用一样在线程之间传递,并且不会改变其含义
然而,这就引出了问题2:
您不应该从创建UI控件的线程以外的线程访问UI控件(这意味着从控件派生的任何类型,包括表单)。。
如果必须这样做,则必须将访问控件的调用封送到创建该控件的线程,例如使用调用/开始调用(还有其他方法)
下面是对代码的修改,以实现所需的功能,另外还有一个更复杂的示例,演示了多个线程“开关”:在UI线程上收集感兴趣的状态,在后台线程上使用它执行工作,然后在UI线程上显示结果
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 &= 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
请提供一个最简单的例子来演示所描述的行为。我毫不怀疑这个解决方案是琐碎的,但如果没有看到一些代码,就很难判断问题出在哪里。如果有人能建议如何解决这个问题,我只是这样做了,请问你,因为我对vb.net非常陌生,我没有得到你编写的代码,但是使用vari形式艾布尔是helpfull@user3781458,如果上面的代码在您看来像是胡言乱语,那是因为a)它依赖于异步编程作为一种艺术形式时的低级构造;现代VB.NET中有更好的工具可用,即Task
和async/Await;以及b)它需要了解委托和闭包,这对于编写高质量的异步代码是必不可少的(并且对于使用某些其他技术(如LINQ)非常有用)。