Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
交叉线程跨类vb.net问题_Vb.net_Multithreading_Function - Fatal编程技术网

交叉线程跨类vb.net问题

交叉线程跨类vb.net问题,vb.net,multithreading,function,Vb.net,Multithreading,Function,我有我的表单类,还有第二个模块,有一些特殊的函数, 当我单击表单上的一个按钮时,我在一个单独的线程中运行第二个模块中的一个公共函数(稍后从第二个模块中运行其他公共函数),我设置了SetApartmentState(ApartmentState.STA),并尝试使用deltage sub和CheckForIllegalCrossThreadCalls=False,但问题仍然是我的线程函数(位于第二个模块上)无法访问我的表单控件,但是当我将函数移动到表单类时,所有功能都会再次工作,您建议如何解决此问

我有我的表单类,还有第二个模块,有一些特殊的函数, 当我单击表单上的一个按钮时,我在一个单独的线程中运行第二个模块中的一个公共函数(稍后从第二个模块中运行其他公共函数),我设置了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)非常有用)。