在由另一个类VB.nET的线程引发的事件上更新GUI项

时间:2012-09-19 22:00:48

标签: vb.net event-handling multithreading

如何使用另一个类的线程接收的消息更新GUI中的数据?

我有一个带有从服务器接收数据的线程的类。每当从服务器收到消息时,该线程就会引发一个事件。此事件在Starter Class(包含GUI的主类)中处理。 事件处理程序(比如DisplayData()必须显示其他类接收的消息。 我的代码就像这样

Class GUI
    receiverObj = New Receiver()
    Addhandler receiverObj.MessageAlert, Addressof DisplayData
    ...
    ...
    Sub DisplayData()
        Dim str As receiverObj.ReceiveData

        lbEvents.Add.Items(str)   ' lbEvents is a ListBox inside the GUI that displays messages from Receiver 
    End Sub
End Class


Class Receiver

    Public Event MessageAlert()
    Sub New ()
        MyTcpClient = New TcpClient(hostIP, port)               
        MyTcpClient.GetStream.BeginRead(ReceiveData, 0, PacketSize, AddressOf ReceiveStream, Nothing)
    End Sub

    Public Sub ReceiveStream(ByVal ar As IAsyncResult)
        Dim ByteCount As Integer

        Try
            ByteCount = MyTcpClient.GetStream.EndRead(ar)
            Dim t As New Threading.Thread(Sub() RaiseEvent MessageAlert())
            MyTcpClient.GetStream.BeginRead(ReceiveData, 0, PacketSize, AddressOf ReceiveStream, Nothing)
     End Sub
End Class

窗口崩溃或挂起,列表框不显示数据。抛出异常说

跨线程操作无效:控制xxx从其创建的线程以外的线程访问。

有人可以提出修复此错误的方法吗? 如何使用另一个类的线程接收的消息更新GUI中的数据?

1 个答案:

答案 0 :(得分:4)

必须在创建GUI的线程上更新Windows应用程序的GUI元素。

要解决此问题,有一个名为Invoke的方法允许您触发委托,它可以确保控制权传递给GUI线程并执行您正在尝试的更新。

你需要做一些事情来完成这项工作:

  1. 委托类型,例如

    Delegate Sub MyGUIUpdateDelegate()
  2. 您的代理类型的变量

    Public myGUIUpdateDelegate as MyGUIUpdateDelegate
  3. 具有与委托相匹配的签名并完成工作的方法:

    Public Sub MyGuiEventHandler()
    ' Do work on proper GUI thread, via Control.Invoke, ' such as listbox population
    If (Me.InvokeRequired) Then Me.Invoke( myGUIUpdateDelegate) Else // do control specific work, we're on the GUI thread here End If

    End Sub

  4. 为您的代理人分配事件处理程序:

    myGUIUpdateDelegate = New MyGuiUpdateDelegate(AddressOf myForm.MyGuiEventHandler)
  5. 通过Control.Invoke调用updater方法从事件线程调用正确的线程(假设 您的表单实例变量名为myForm):

    myForm.Invoke(myForm.myGUIUpdateDelegate);
  6. 这至少是一个可以帮助你入门的框架。这个想法是,想要引发更新的后台线程不应该(并且实际上不能)进行直接的GUI更新。启动上下文切换到GUI线程的正确方法是调用Invoke方法在适当的GUI线程上调用GUI更新程序。

    此外,如果您需要将参数传递给您的委托,只需更改您定义的Delegate的签名以包含参数,并修改Invoke方法以在处理程序中提供参数,并将第二个参数更改为调用

    希望这有帮助。