在另一个类VB.nET的线程引发的事件上更新GUI项目 [英] Updating GUI items upon an event raised by a thread of another class VB.nET

查看:168
本文介绍了在另一个类VB.nET的线程引发的事件上更新GUI项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我有一个类,从服务器接收数据的线程。当线程从服务器获取消息时,该线程会引发一个事件。此事件在Starter Class(包含GUI的主类)内部处理。
事件处理程序(例如 DisplayData()必须显示另一个类收到的消息
我的代码就是这样

 类GUI 
receiverObj =新的Receiver()
Addhandler receiverObj.MessageAlert,Addressof DisplayData
...
...
Sub DisplayData()
Dim str As receiverObj.ReceiveData

lbEvents.Add.Items(str)'lbEvents是显示在GUI中的ListBox来自Receiver的消息
End Sub
结束类


类接收者

公共事件MessageAlert()
Sub New()
MyTcpClient =新的TcpClient(hostIP,端口)
MyTcpClient.GetStream.BeginRead(ReceiveData,0,PacketSize,AddressOf ReceiveStream,Nothing)
End Sub

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

尝试
ByteCount = MyTcpClient.GetS tream.EndRead(ar)
Dim t As New Threading.Thread(Sub()RaiseEvent MessageAlert())
MyTcpClient.GetStream.BeginRead(ReceiveData,0,PacketSize,AddressOf ReceiveStream,Nothing)
End Sub
结束类

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



跨线程操作无效:从除了创建线程之外的线程访问的控制xxx。



有人可以建议一种方法来解决这个错误?
如何使用另一个类的线程接收的消息更新GUI中的数据?

解决方案

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



要解决这个问题,有一种叫做Invoke的方法,可以启动一个可以确保控件传递给GUI线程并执行的委托您正在尝试的更新。



您需要几件事才能使其发挥作用:


  1. 一个代表类型,例如

     委托Sub MyGUIUpdateDelegate() / pre> 

  2. 代表类型的变量

      public myGUIUpdateDelegate as MyGUIUpdateDelegate  


  3. 一种方法,具有与委托相匹配的签名并进行工作: p>

      Public Sub MyGuiEventHandler()

    '通过Control.Invoke执行正确的GUI线程,
    '如列表框人口

    如果(Me.InvokeRequired)然后
    Me.Invoke(myGUIUpdateDelegate)
    Else
    //做控制具体工作,我们在这里的GUI线程
    如果



    End Sub

     


  4. 事件处理程序分配给您的委托:



    myGUIUpdateDelegate =新建MyGuiUpdateDel egate(AddressOf myForm.MyGuiEventHandler)


  5. 通过Control.Invoke调用更新程序到正确的线程事件线程(假设
    您的表单实例变量名为myForm):



    myForm.Invoke(myForm.myGUIUpdateDelegate);


这至少是一个应该可以帮助您开始的框架。这个想法是,想要引导更新的后台线程不应该(并且实际上不能)进行直接的GUI更新。启动上下文切换到GUI线程的正确方法是调用Invoke方法调用正确的GUI线程上的GUI更新程序。



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



希望这有帮助。


How to update data in GUI with messages that are being received by a thread of another class ?

I have a class with a thread that receives data from a server. This thread raises an event whenever it gets a message from the server. This event is handled inside the Starter Class (main class which contains the GUI). The event handler (say DisplayData() has to display the message received by the other class. My code is like this

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

The Window crashes or hangs and the listbox does not display data. Throws exception saying

Cross-thread operation not valid: Control xxx accessed from a thread other than the thread it was created on.

Can anybody suggest a way to fix this error ? How to update data in GUI with messages that are being received by a thread of another class ?

解决方案

Updates to GUI elements of a Windows application must take place on the thread that created the GUI.

To fix this, there's a method called Invoke that allows you to fire a delegate that can ensure control is passed to the GUI thread and perform the update you are attempting.

You need a few things to make this work:

  1. A Delegate type , such as

    Delegate Sub MyGUIUpdateDelegate()

  2. A variable of the type of your delegate

    Public myGUIUpdateDelegate as MyGUIUpdateDelegate

  3. A method having a signature that matches the delegate and does the work:

    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. An assignment of the event handler to your delegate:

    myGUIUpdateDelegate = New MyGuiUpdateDelegate(AddressOf myForm.MyGuiEventHandler)

  5. A call to your updater method via Control.Invoke to the proper thread from the event thread (assuming your form instance variable is named myForm):

    myForm.Invoke(myForm.myGUIUpdateDelegate);

That's at least a framework that should help you get started. The idea is that the background thread that wants to induce the update should not (and in reality, cannot) make direct GUI updates. The proper way to initiate a context switch to the GUI thread is by calling the Invoke method to call the GUI updater on the proper GUI thread.

Additionally, if you need to pass parameters to your delegate, simply alter the signature of the Delegate you define to include the parameter(s), and modify the Invoke method to provide the arguments in the handler, and the 2nd argument to Invoke.

Hope this helps.

这篇关于在另一个类VB.nET的线程引发的事件上更新GUI项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆