Vb.net - Cross-threading exception by closing a form
-
06-07-2021 - |
Frage
I'm working on an application to read something from a serial port (COMM-port). In short, it works like this: when you work in a bar or restaurant, before you can enter something in the register, you have to scan a sort of card. If this card returns a good number, you can enter something.
So, there has to be a form that listens to the serial port and checks whether someone scans a card and if it's a card with good rights.
If the person has the good rights, the form can be closed and another form is called.
Now, in code:
Here, the MenuForm is loaded (the form that has to be accesible after the correct code was read). I call the frmWaiterKey to show up.
Private Sub frmMenu_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim oForm As frmWaiterKey = New frmWaiterKey()
oForm.ShowDialog()
End Sub
The code of the class frmWaiterKey:
Private Sub frmWaiterKey_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
nameArray = SerialPort.GetPortNames
OpenComPort()
AddHandler myComPort.DataReceived, SerialDataReceivedEventHandler1
End Sub
Sub OpenComPort()
Try
' Get the selected COM port's name
' from the combo box.
If Not myComPort.IsOpen Then
myComPort.PortName = _
nameArray(0).ToString()
' Get the selected bit rate from the combo box.
myComPort.BaudRate = CInt(9600)
' Set other port parameters.
myComPort.Parity = Parity.None
myComPort.DataBits = 8
myComPort.StopBits = StopBits.One
myComPort.Handshake = Handshake.None
'myComPort.ReadTimeout = 3000
'myComPort.WriteTimeout = 5000
' Open the port.
myComPort.Open()
End If
Catch ex As InvalidOperationException
MessageBox.Show(ex.Message)
Catch ex As UnauthorizedAccessException
MessageBox.Show(ex.Message)
Catch ex As System.IO.IOException
MessageBox.Show(ex.Message)
End Try
End Sub
Sub CloseComPort()
Using myComPort
If (Not (myComPort Is Nothing)) Then
' The COM port exists.
If myComPort.IsOpen Then
' Wait for the transmit buffer to empty.
Do While (myComPort.BytesToWrite > 0)
Loop
End If
End If
End Using
End Sub
Private SerialDataReceivedEventHandler1 As New SerialDataReceivedEventHandler(AddressOf DataReceived)
' Specify the routine that runs when
' a DataReceived event occurs at myComPort.
' This routine runs when data arrives at myComPort.
Friend Sub DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
Dim newReceivedData As String
' Get data from the COM port.
newReceivedData = myComPort.ReadExisting
newReceivedData = newReceivedData.Trim()
MsgBox(newReceivedData)
If newReceivedData.Equals("00150324294764") Then
CloseComPort()
Me.Close()
End If
End Sub
I get an error in the last line: Me.Close() I get the point: I call the form frmWaiterKey from the frmMenu and can't close it here... But I have no idea how to solve this problem.
I hope someone can help me or tell me what I'm doing wrong.
Lösung
First, you need to make a method like this:
Private Sub CloseMe()
If Me.InvokeRequired Then
Me.Invoke(New MethodInvoker(AddressOf CloseMe))
Exit Sub
End If
Me.Close()
End Sub
Then, close your form by calling that method, like this:
If newReceivedData.Equals("00150324294764") Then
CloseComPort()
CloseMe()
End If
The reason this is necessary is because all UI activity in WinForms must be performed from the same thread. Since the DataReceived
method is being called from another thread, it must get back onto the UI thread before it can close the form. The InvokeRequired
property returns true if you are on any thread other than the UI thread, and the Invoke
method invokes the given method from the UI thread.