Results 1 to 14 of 14

Thread: async threads and adding data to a treeview without using invoke method

  1. #1

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632

    async threads and adding data to a treeview without using invoke method

    I have a class, which raises an evert to the UI.
    VB Code:
    1. Private Withevents _Conn As MyConnection
    2.  
    3. Private Sub _Conn_Data(ByVal Data As String) Handles _Conn.Data
    4.    Treeview1.Nodes.Add Data
    5. End Sub
    the thing is that _conn calls another thread, which wiats for data. When data arrives the above event is raised, but .NET doesn't like adding the data to a treeview as the event has come from another thread.
    To get this to work I must do:
    VB Code:
    1. Private _Data As String
    2.  
    3. Private Sub _Conn_Data(ByVal Data As String) Handles _Conn.Data
    4.    _Data =  Data
    5.    Treeview1.Invoke(CType(AddressOf addnewnode, MethodInvoker))
    6. End Sub
    7.  
    8. Private Sub AddNewNode()
    9.    Treeview1.Nodes.Add _Data
    10. End Sub
    this is not good.
    What I would like is the event to be raised in the correct thread.
    Someone mentioned that queues could be used.
    The that I use is this:
    VB Code:
    1. Imports System.Net.Sockets
    2. Imports System.IO
    3. Imports System.Text
    4.  
    5. Public Class TCPConnection
    6.  
    7.     Public Event DataArrived(ByVal Data() As Byte)
    8.     Public Event Disconnected()
    9.  
    10.     Private Const READ_BUFFER_SIZE As Integer = 255
    11.  
    12.     Private _ReadCallBack As AsyncCallback
    13.  
    14.     Private _HostAddress As String
    15.     Private _Port As Integer
    16.  
    17.     Private _TCPClient As TcpClient
    18.  
    19.     Private _NS As NetworkStream
    20.     Private _SW As StreamWriter
    21.     ' Private _SR As StreamReader
    22.  
    23.     Private _Buffer(READ_BUFFER_SIZE - 1) As Byte
    24.  
    25.     Public Sub New(ByVal HostAddress As String, ByVal Port As Integer)
    26.         _HostAddress = HostAddress
    27.         _Port = Port
    28.         Connect()
    29.     End Sub
    30.  
    31.     Public ReadOnly Property HostAddress() As String
    32.         Get
    33.             Return _HostAddress
    34.         End Get
    35.     End Property
    36.  
    37.     Public ReadOnly Property Port() As Integer
    38.         Get
    39.             Return _Port
    40.         End Get
    41.     End Property
    42.  
    43.     Public Sub Connect()
    44.         _TCPClient = New TcpClient(_HostAddress, _Port)
    45.         _NS = _TCPClient.GetStream()
    46.         '_SR = New StreamReader(_NS, Encoding.ASCII)
    47.         _SW = New StreamWriter(_NS, Encoding.ASCII)
    48.         _SW.AutoFlush = True
    49.         StartAsyncRead()
    50.     End Sub
    51.  
    52.     Public Sub Disconnect()
    53.         _TCPClient.Close()
    54.         _TCPClient = Nothing
    55.         RaiseEvent Disconnected()
    56.     End Sub
    57.  
    58.     Public Sub SendData(ByRef Data As String)
    59.         _SW.Write(Data)
    60.     End Sub
    61.  
    62.     Private Sub StartAsyncRead()
    63.         _ReadCallBack = New AsyncCallback(AddressOf DoRead)
    64.         _NS.BeginRead(_Buffer, 0, READ_BUFFER_SIZE, _ReadCallBack, Nothing)
    65.     End Sub
    66.  
    67.     Private Sub DoRead(ByVal Result As IAsyncResult)
    68.         Try
    69.             Dim BytesRead As Integer = _NS.EndRead(Result)
    70.  
    71.             If BytesRead < 1 Then
    72.                 Disconnect()
    73.             Else
    74.                 Dim Data(BytesRead - 1) As Byte
    75.  
    76.                 _Buffer.Copy(_Buffer, 0, Data, 0, BytesRead)
    77.                 RaiseEvent DataArrived(Data)
    78.                 StartAsyncRead()
    79.             End If
    80.         Catch e As Exception
    81.             Disconnect()
    82.         End Try
    83.     End Sub
    84. End Class
    The function StartAsyncRead is the one that starts a new thread for receiving data.

    Woka

  2. #2
    Your Ad Here! Edneeis's Avatar
    Join Date
    Feb 2000
    Location
    Moreno Valley, CA (SoCal)
    Posts
    7,339

    Re: async threads and adding data to a treeview without using invoke method

    If you have a reference to the form or controls then you could marshal the call back to the UI thread before actually raising the event.

  3. #3

  4. #4
    Your Ad Here! Edneeis's Avatar
    Join Date
    Feb 2000
    Location
    Moreno Valley, CA (SoCal)
    Posts
    7,339

    Re: async threads and adding data to a treeview without using invoke method

    Sorry about that I meant to include when with my original post but got distracted. Here you go. I tried to highlight the real 'meat' of it because I had to do some other crap to simulate your threading situation and that part isn't something you need.

    To make it work in your situation you'd need to add some sort of ThreadRoot to the TCPConnection class and make it required. Then you would need to make a delegate for the DataArrived event so it can be called via Invoke. Then you'd need to make a hidden/protected method to simply raise the event. Last you would just change your RaiseEvent code to use something like this instead of just RaiseEvent DataArrived(Data):
    VB Code:
    1. 'check if the threadroot is in a different thread
    2.             If _ThreadRoot.InvokeRequired Then
    3.                 'the threadroot IS in a different thread so create a delegate
    4.                 'and then invoke that delegate on the control's thread
    5.                 Dim del As New DataArrivedHandler(AddressOf Me.FireDataArrivedEvent)
    6.                 _ThreadRoot.Invoke(del, New Object() {Data})
    7.             Else
    8.                 'the threadroot is NOT in a different thread so fire it locally
    9.                 FireDataArrivedEvent(Data)
    10.             End If

    Then nothing would be different in the consumer code and the event would be like any other non-threaded event.
    Attached Files Attached Files
    Last edited by Edneeis; Sep 4th, 2005 at 05:55 PM.

  5. #5

  6. #6

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632

    Re: async threads and adding data to a treeview without using invoke method

    OK...I see how this code works. Similar to what I have now where it uses Control.Invoke.
    VB Code:
    1. Private _ThreadRoot As Control
    Now, what I am looking for is to change this to:
    VB Code:
    1. Private _ThreadRoot As MyOwnClassObject
    Where MyOwnClassObject is just a class that raises events to the UI.

    Is this possible?

    Woka

  7. #7

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632

    Re: async threads and adding data to a treeview without using invoke method

    What I have is 2 classes.

    Class1 and Class2

    Class1 is declared on a form using:
    VB Code:
    1. Private Withevents Woof As Class1
    Class2 is declared in exactly the same way, but inside class1. So basically Class2 raises events into class1, then depending on these events class1 raises further events to the UI.
    Now I ALWAYS want class1 in the same thread as the form.
    It's class2 that executes code async.
    So, I want to "marshal", invoke, or whatever it's called, so that class2 raises the event into class1 in the correct thread? make sense?
    All the examples I have seen involve using a form, or in your example, a control to work out what thread the event needs to be invoked 2.

    Am I making sense?
    Sorry if my terminology is incorrect.

    Woka

  8. #8
    Your Ad Here! Edneeis's Avatar
    Join Date
    Feb 2000
    Location
    Moreno Valley, CA (SoCal)
    Posts
    7,339

    Re: async threads and adding data to a treeview without using invoke method

    The code I gave would then need to be in your class2. The reason a form (which is a control) or control is used is because it has the Invoke and InvokeRequired methods which make all the magic happen. So if you don't pass a control reference to Class2 then you'll need to reproduce that functionality. The best bet on that is to use Reflector to see what the Framework is doing in these methods BUT I think it'll be more trouble then its worth and I'd recommend just passing a control.

    So Class1 would need the ThreadRoot but it wouldn't use it except to pass to Class2 which would alos have it.

    One shortcut that might help is to have Class2 inherit from Control to get the functionality.
    Last edited by Edneeis; Sep 5th, 2005 at 01:39 PM.

  9. #9

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632

    Re: async threads and adding data to a treeview without using invoke method

    Yup. I agree with you there...however...could my class1 not implement ISynchronizeInvoke?
    VB Code:
    1. Public Class Class1
    2.     Implements System.ComponentModel.ISynchronizeInvoke
    3.  
    4.     Public Function BeginInvoke(ByVal method As System.Delegate, ByVal args() As Object) As System.IAsyncResult Implements System.ComponentModel.ISynchronizeInvoke.BeginInvoke
    5.  
    6.     End Function
    7.  
    8.     Public Function EndInvoke(ByVal result As System.IAsyncResult) As Object Implements System.ComponentModel.ISynchronizeInvoke.EndInvoke
    9.  
    10.     End Function
    11.  
    12.     Public Function Invoke(ByVal method As System.Delegate, ByVal args() As Object) As Object Implements System.ComponentModel.ISynchronizeInvoke.Invoke
    13.  
    14.     End Function
    15.  
    16.     Public ReadOnly Property InvokeRequired() As Boolean Implements System.ComponentModel.ISynchronizeInvoke.InvokeRequired
    17.         Get
    18.  
    19.         End Get
    20.     End Property
    21. End Class
    Then I pass class1 to class2...
    Now all I need to figure out is what code to add into those subs etc

    WOka

  10. #10
    Your Ad Here! Edneeis's Avatar
    Join Date
    Feb 2000
    Location
    Moreno Valley, CA (SoCal)
    Posts
    7,339

    Re: async threads and adding data to a treeview without using invoke method

    Yes that is the tricky part. I took a look at what Control is doing and it is using Application.GetParkedWindow and the Thread.Context to find out what thread the hWnd handle for the control was created on. I still think it'll be more hassle then its worth but if you want to know how Control implements the ISynchronizeInvoke ust download Reflector and check it out.

    http://www.aisto.com/roeder/dotnet/

  11. #11

  12. #12
    Your Ad Here! Edneeis's Avatar
    Join Date
    Feb 2000
    Location
    Moreno Valley, CA (SoCal)
    Posts
    7,339

    Re: async threads and adding data to a treeview without using invoke method

    Yeah I had a feeling you'd saw that.

  13. #13

    Thread Starter
    Super Moderator Wokawidget's Avatar
    Join Date
    Nov 2001
    Location
    Headingly Occupation: Classified
    Posts
    9,632

    Re: async threads and adding data to a treeview without using invoke method

    Hahaha...Hmmmm...OK.
    I have found the following, but am not sure how this helps me

    Can't seem to find any decent help stuff on it.

    WOka
    Attached Images Attached Images  

  14. #14
    Your Ad Here! Edneeis's Avatar
    Join Date
    Feb 2000
    Location
    Moreno Valley, CA (SoCal)
    Posts
    7,339

    Re: async threads and adding data to a treeview without using invoke method

    That is the info on the Interface itself but you want the something that implements it. Try looking up Control and check out its Invoke and InvokeRequired methods then press space to get the code. Also if you see a method that is used inside one of those methods you can click it to go to its code as well. Warning though all of the methods that Control uses take a control as a parameter because the control is where it is getting the window handle from. Control has a whole infrastructure for handling handles and the like.
    Attached Images Attached Images  
    Last edited by Edneeis; Sep 5th, 2005 at 05:09 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width