Results 1 to 13 of 13

Thread: [RESOLVED] Class events question

  1. #1

    Thread Starter
    Addicted Member
    Join Date
    Mar 2010
    Location
    Southeast Michigan
    Posts
    155

    Resolved [RESOLVED] Class events question

    I set up a class with an event as shown here :
    Code:
    Imports System.IO.Ports
    Public Class CommPort
        Dim _msg As String
        Dim WithEvents SerialPort As New SerialPort
        Public Sub New(ByVal portID As String)
            If SerialPort.IsOpen Then
                SerialPort.Close()
            End If
    
            Try
                With SerialPort
                    .PortName = portID
                    .BaudRate = 9600
                    .Parity = IO.Ports.Parity.None
                    .DataBits = 8
                    .StopBits = IO.Ports.StopBits.One
                End With
                SerialPort.Open()
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try
        End Sub
    
        Public Event DataReceived(ByVal message As String)
    
        Private Sub ReadData(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
            Dim _bytes As Integer = SerialPort.BytesToRead
            _msg = ""
            For i As Integer = 0 To _bytes - 1
                _msg = String.Concat(_msg, Chr(SerialPort.ReadChar))
            Next
            RaiseEvent DataReceived(_msg)
        End Sub
    End Class
    And from the main program am using this code :
    Code:
    Public Class Main
        Dim WithEvents commTest As New CommPort("COM1")
    
    Private Sub ProcessCommData(ByVal message As String) Handles commTest.DataReceived
            txtSONumber.Text = message
        End Sub
    End Class
    When the event triggers I get an error in the program where trying to update the forms text that says "Cross-thread operation not valid: Control 'txtSONumber' accessed from a thread other than the thread it was created on."

    Am I using the custom event incorrectly?

    Thanks in advance for your help.

  2. #2
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: Class events question

    No, but your custom event happens in another thread. You need to invoke a sub that changes the txtSONumber text in the UI thread.

    Add this to your code:
    vb.net Code:
    1. Public Delegate Sub InvokeWithStringDelegate(ByVal Text As String)
    2.  
    3.     Public Sub ChangeTextboxText(ByVal Text As String)
    4.         If txtSONumber.InvokeRequired Then
    5.             Me.Invoke(New InvokeWithStringDelegate(AddressOf ChangeTextboxText), New Object() {Text})
    6.         Else
    7.             txtSONumber.Text = Text
    8.         End If
    9.     End Sub
    10.  
    11.     Private Sub ProcessCommData(ByVal message As String) Handles commTest.DataReceived
    12.         ChangeTextboxText(message)
    13.     End Sub

  3. #3
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Class events question

    I think the code is fine... it's just in the wrong spot...

    This code:
    Code:
        Dim WithEvents commTest As New CommPort("COM1")
    
    Private Sub ProcessCommData(ByVal message As String) Handles commTest.DataReceived
            txtSONumber.Text = message
        End Sub
    Should be in the form's class... not the main class...

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  4. #4
    Hyperactive Member Philly0494's Avatar
    Join Date
    Apr 2008
    Posts
    485

    Re: Class events question

    Quote Originally Posted by techgnome View Post
    I think the code is fine... it's just in the wrong spot...

    This code:
    Code:
        Dim WithEvents commTest As New CommPort("COM1")
    
    Private Sub ProcessCommData(ByVal message As String) Handles commTest.DataReceived
            txtSONumber.Text = message
        End Sub
    Should be in the form's class... not the main class...

    -tg
    No that isn't his problem at all, he is operating in the correct class, just not on the same thread which is why the invoking is required

    He would have likely gotten an error before he compiled if he wasn't in the right class, instead of a runtime error

  5. #5
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Class events question

    I get what you're saying... but I don't see how it's on a different thread, unless there's something that wasn't shared as part of the code. It's not like it would be the first time incomplete code was posted. ;P

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  6. #6
    Hyperactive Member Philly0494's Avatar
    Join Date
    Apr 2008
    Posts
    485

    Re: Class events question

    Quote Originally Posted by techgnome View Post
    I get what you're saying... but I don't see how it's on a different thread, unless there's something that wasn't shared as part of the code. It's not like it would be the first time incomplete code was posted. ;P

    -tg
    oh well he is using a CommPort which receives data on its own seperate thread, thus the DataReceived event is inherently on a different thread

    very similar to WinSock's data receiving/connection request etc

  7. #7

    Thread Starter
    Addicted Member
    Join Date
    Mar 2010
    Location
    Southeast Michigan
    Posts
    155

    Re: Class events question

    Thanks cicatrix, and everyone else, for such a quick response. That took care of my error. Interesting how that works, checking for the InvokeRequired, which I've never used before, and then returning to update the textbox.

    Thanks for your help!

  8. #8
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,687

    Re: Class events question

    Ahh.... OK... makes total sense then.

    See? It is possible to learn something new everyday.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,109

    Re: Class events question

    The solution works, but I don't like it.

    The serial port already raises a datareceived event. Since you are wrapping the port in a different class, do you really want to have that class deal with events on different threads? Do you want any class (form) that uses your wrapper class to have to be aware that the datareceived event is coming in on a different thread? I would say that it would be better to raise the event on the UI thread and be done with it. Otherwise, what is the advantage to wrapping the serial port object?

    If you would prefer to raise the event on the UI thread, take a look at the UDP class I posted at about #7 in this thread:

    http://www.vbforums.com/showthread.php?t=509619

    In particular, look at how I used the SynchronizationContext. I save the context before starting the thread (you could do that in your class constructor, which will mean that the context saved will be for the thread that created the object, though the object is not thread specific). You then add a sub that raises the actual event, and when you want to raise the event, you post a call to that sub on the context. It takes only a couple lines, and your events come out on the thread that created the class.
    My usual boring signature: Nothing

  10. #10

    Thread Starter
    Addicted Member
    Join Date
    Mar 2010
    Location
    Southeast Michigan
    Posts
    155

    Re: Class events question

    Shaggy Hiker,

    Thanks. I'm looking at your previous post now and reading up on SynchronizationContext. No doubt I'll have more questions.

    thanks again for your input.

  11. #11

    Thread Starter
    Addicted Member
    Join Date
    Mar 2010
    Location
    Southeast Michigan
    Posts
    155

    Re: Class events question

    Ok, let's see if I'm getting this.

    The myContext = System.Threading.SynchronizationContext.Current needs to be set from my class that is wrapping the serial port class. Then, within the SerialPort.DataReceived event of the serial port class the myContext.Post is done so that I can raise the wrapper classes custom event.

    Here's what I changed:

    Code:
    Imports System.IO.Ports
    Public Class CommPort
        Dim _msg As String
        Dim WithEvents SerialPort As New SerialPort
        Dim myContext As System.Threading.SynchronizationContext
        Public Sub New(ByVal portID As String)
            myContext = System.Threading.SynchronizationContext.Current
            If SerialPort.IsOpen Then
                SerialPort.Close()
            End If
    
            Try
                With SerialPort
                    .PortName = portID
                    .BaudRate = 9600
                    .Parity = IO.Ports.Parity.None
                    .DataBits = 8
                    .StopBits = IO.Ports.StopBits.One
                End With
                SerialPort.Open()
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try
        End Sub
    
        Public Event DataReceived(ByVal message As String)
        Private Sub triggerDataReceived(ByVal state As Object)
            RaiseEvent DataReceived(_msg)
        End Sub
    
        Private Sub ReadData(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
            Dim _bytes As Integer = SerialPort.BytesToRead
            _msg = ""
            For i As Integer = 0 To _bytes - 1
                _msg = String.Concat(_msg, Chr(SerialPort.ReadChar))
            Next
            'RaiseEvent DataReceived(_msg)
            myContext.Post(AddressOf triggerDataReceived, Nothing)
        End Sub
    End Class
    Then, in the UI code:
    Code:
        Private Sub ProcessCommData(ByVal message As String) Handles commTest.DataReceived
            txtSONumber.Text = message
        End Sub
    It works but wanted to make sure I'm using this method correctly. Since I haven't done a lot of programming, especially recently, I'd love to hear any other feedback you have on anything you see.

    As always, thanks so much for the help.

  12. #12
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,109

    Re: Class events question

    I believe you have done it the way that I would have. I particularly like the fact that the event is now raised on the thread that created the wrapper for the serial port, which is where you would expect the event to be raised normally.
    My usual boring signature: Nothing

  13. #13

    Thread Starter
    Addicted Member
    Join Date
    Mar 2010
    Location
    Southeast Michigan
    Posts
    155

    Re: Class events question

    Thanks Shaggy Hiker.
    Dave

    Helpful information I've found here so far : The Definitive "Passing Data Between Forms" : Restrict TextBox to only certain characters, numeric or symbolic :
    .NET Regex Syntax (scripting) : .NET Regex Language Element : .NET Regex Class : Regular-Expressions.info
    Stuff I've learned here so far : Bing and Google are your friend. Trying to help others solve their problems is a great learning experience

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