J
JDS
I am trying to get data from several devices on serial ports back to a
form. I am struggling with handling the threading issues. I am also
trying to write the code for the devices in a self-contained class to
make it easier to reuse.
I have managed to get it to work by passing the form as a callback
object to the device class (and then using BeginInvoke on that
callback object in the Receiver method). However, this does not seem
to be a very elegant solution and seems to go against the principle of
object programming.
I thought that using events was equivalent to using delegates to
transfer control to a different thread but looks like am am doing
something wrong! The resulting error message is: "Cross-thread
operation not valid: Control 'tbLog' accessed from a thread other than
the thread it was created on."
Any help would be greatly appreciated.
The following is an extract from the code. The bulk of it has been
removed including the error handling but I hope I have left in the
relevant parts.
CODE:
'Class for each device
Public Class Device
Private mintID As Integer
Private WithEvents mIOPort As SerialPort
Private Delegate Sub RxDelegate(ByVal RxData As String)
Private mDlgt As New RxDelegate(AddressOf ProcessRxData)
Private mRslt As System.IAsyncResult
'....
Public Event RxData(ByVal intID As Integer, ByVal strData As
String)
Private Sub Receiver(ByVal sender As Object, ByVal e As
SerialDataReceivedEventArgs) Handles mIOPort.DataReceived
mRslt = mDlgt.BeginInvoke(mIOPort.ReadLine, Nothing, Nothing)
End Sub
Private Sub ProcessRxData(ByVal strData As String)
RaiseEvent RxData(mintID, strData)
mDlgt.EndInvoke(mRslt)
End Sub
'....
End Class
'--------------------------------------------------------
'Class for collection of devices
Public Class DeviceColl
Inherits Dictionary(Of Integer, clsScaleIF)
Public Event RxData(ByVal ID As Integer, ByVal strData As String)
'....
Public Overloads Sub Add(ByVal ID As Integer, ByVal PortNum As
Nullable(Of Int16))
Dim NewDevice = New Device(ID, PortNum)
....
AddHandler NewDevice.RxData, AddressOf RxDataHandler
End Sub
Public Sub RxDataHandler(ByVal ID As Integer, ByVal strData As
String)
RaiseEvent RxData(ID, strData)
End Sub
'....
End Class
'--------------------------------------------------------
'Main form for user interface
Public Class frmMain
Dim WithEvents mDeviceList As DeviceColl
'....
Public Sub Device_Rx(ByVal intID As Integer, ByVal strData As
String) Handles mDeviceList.RxData
Log("Rx" & intID.ToString & ": " & strData)
End Sub
Private Sub Log(ByVal strText As String)
tbLog.SelectedText = strText
End Sub
'....
End Class
form. I am struggling with handling the threading issues. I am also
trying to write the code for the devices in a self-contained class to
make it easier to reuse.
I have managed to get it to work by passing the form as a callback
object to the device class (and then using BeginInvoke on that
callback object in the Receiver method). However, this does not seem
to be a very elegant solution and seems to go against the principle of
object programming.
I thought that using events was equivalent to using delegates to
transfer control to a different thread but looks like am am doing
something wrong! The resulting error message is: "Cross-thread
operation not valid: Control 'tbLog' accessed from a thread other than
the thread it was created on."
Any help would be greatly appreciated.
The following is an extract from the code. The bulk of it has been
removed including the error handling but I hope I have left in the
relevant parts.
CODE:
'Class for each device
Public Class Device
Private mintID As Integer
Private WithEvents mIOPort As SerialPort
Private Delegate Sub RxDelegate(ByVal RxData As String)
Private mDlgt As New RxDelegate(AddressOf ProcessRxData)
Private mRslt As System.IAsyncResult
'....
Public Event RxData(ByVal intID As Integer, ByVal strData As
String)
Private Sub Receiver(ByVal sender As Object, ByVal e As
SerialDataReceivedEventArgs) Handles mIOPort.DataReceived
mRslt = mDlgt.BeginInvoke(mIOPort.ReadLine, Nothing, Nothing)
End Sub
Private Sub ProcessRxData(ByVal strData As String)
RaiseEvent RxData(mintID, strData)
mDlgt.EndInvoke(mRslt)
End Sub
'....
End Class
'--------------------------------------------------------
'Class for collection of devices
Public Class DeviceColl
Inherits Dictionary(Of Integer, clsScaleIF)
Public Event RxData(ByVal ID As Integer, ByVal strData As String)
'....
Public Overloads Sub Add(ByVal ID As Integer, ByVal PortNum As
Nullable(Of Int16))
Dim NewDevice = New Device(ID, PortNum)
....
AddHandler NewDevice.RxData, AddressOf RxDataHandler
End Sub
Public Sub RxDataHandler(ByVal ID As Integer, ByVal strData As
String)
RaiseEvent RxData(ID, strData)
End Sub
'....
End Class
'--------------------------------------------------------
'Main form for user interface
Public Class frmMain
Dim WithEvents mDeviceList As DeviceColl
'....
Public Sub Device_Rx(ByVal intID As Integer, ByVal strData As
String) Handles mDeviceList.RxData
Log("Rx" & intID.ToString & ": " & strData)
End Sub
Private Sub Log(ByVal strText As String)
tbLog.SelectedText = strText
End Sub
'....
End Class