SerialPort.DataReceived event not firing - vb.net

I've defined a SerialPort object as the following:
Public WithEvents SerialComm As New System.IO.Ports.SerialPort
SerialComm is setup and opened in the object constructor and closed when the object is disposed. My handler signature is as follows:
Private Sub OnComm(sender as Object, e as SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
I'm trying to get a DataReceived event to fire from HyperTerminal. After sending some data, I can set a breakpoint and check the value of SerialComm.BytesToRead and see that it has updated to the proper number of bytes.
I have confirmed that the SerialPort is open and is receiving data, but I can't get the event to fire.
I've also tried manually wiring up the event (after removing the WithEvents definition) using AddHandler, but I was still unable to get the event to trigger.
What am I missing?
Update:
This is the class that I'm having trouble with:
Imports System.IO.Ports
Public Class CopyCat
Implements IDisposable
Private RxString As String
Private LastReceiveTime As DateTime
Public WithEvents SerialComm As New SerialPort
Public Property Timeout As TimeSpan
Public Sub New(commPort As String, timeout As TimeSpan)
Me.Timeout = timeout
Enable(commPort)
End Sub
Public Sub New(commPort As String)
Me.New(commPort, TimeSpan.FromMilliseconds(1000))
End Sub
Public Sub Enable()
CommUtilities.SetupComm(SerialComm, commPort, 115200, 8, Parity.Odd, StopBits.One, Handshake.None, System.Text.Encoding.Default)
End Sub
Public Sub Disable()
SerialComm.Close()
End Sub
Private Sub OnComm(sender As Object, e As SerialDataReceivedEventArgs) Handles SerialComm.DataReceived
If(DateTime.Now - LastReceivedTime > Timeout) Then RxString = ""
Do While(SerialComm.BytesToRead > 0)
Dim readChar As String
Dim termChar As Char = Chr(RxString.ToByteList().XorAll())
readChar = SerialComm.ReadChar
RxString &= readChar
if (readChar = termChar) Then
SerialComm.Write((From item In GetResponse(RxString).Build()
Select item.Data).ToRawString)
RxString = ""
End If
Loop
End Sub
Public Function GetResponse(commandString As String) As MessageResponse
Dim response As MessageResponse = MessageResponse.GetMessageResponseFromByteList(commandString.ToByteList())
if (response.GetType = GetType(GetStatusResponse)) Then
response.DataBytes(8).Data = Math.Floor(Rnd() * 255)
response.DataBytes(9).Data = Math.Floor(Rnd() * 255)
End If
Return response
End Function
Private disposedValue as Boolean
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
SerialComm.Dispose()
End If
End If
Me.disposedValue = True
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
End Class

Related

System.Timers.Timer and DataBinding

If I have a class that implements INotifyPropertyChanged, and I have a property in that class that is bound to a label on a form, how do I avoid a Cross-threaded exception if I set the property value from a System.Timers.Timer.Elapsed event handler?
The following code demonstrates the exception.
Imports System.ComponentModel
Imports System.Timers
Public Class Form1
Private thisClass As New aClass
Private WithEvents tmr As New System.Timers.Timer()
Private lbl As System.Windows.Forms.Label
Public Sub New()
InitializeComponent()
'create the label and add it to the form
lbl = New Label
lbl.Text = "some text"
Me.Controls.Add(lbl)
'set the data binding and start a timer
lbl.DataBindings.Add("Text", thisClass, "X")
tmr.Interval = 1000
AddHandler tmr.Elapsed, AddressOf tmr_Elapsed
tmr.Start()
End Sub
Private Sub tmr_Elapsed(sender As Object, e As ElapsedEventArgs)
'change the property value when the timer elapses
thisClass.X = Guid.NewGuid.ToString
End Sub
End Class
Public Class aClass
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private _x As String = ""
Public Property X As String
Get
Return _x
End Get
Set(value As String)
_x = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("X"))
End Set
End Property
End Class
Alternative approach could be to use an asynchronous method to keep updating code on same thread.
Public Class MyForm
Private _viewmodel As MyViewModel
Private _intervalTask As Task
Private _canContinueIntervalRunning As Boolean
Public Sub New()
InitializeComponent()
_viewmodel = New MyViewModel()
CreateLabel() ' Create label and bind to viewmodel property
' Start interval without blocking this code execution
' Later we can use this saved task to make sure that task is complete
_canContinueIntervalRunning = True
_intervalTask = StartInterval()
End Sub
Private Async Function StartInterval() As Task
While _canContinueIntervalRunning
Await Task.Delay(1000)
_viewmodel.X = Guid.NewGuid().ToString()
End While
End Function
Private Async Sub FormClosing(sender as Object, e as FormClosingEventArgs) Handles MyForm.FormClosing
' Set "flag" to false and wait for task to complete
_canContinueIntervalRunning = False
Await _intervalTask
End Sub
End Class
With Await Task.Delay(1000) next line will be executed on same thread, which allows to update form controls without extra effort.
This is simple approach with boolean flag, another way of doing it would be to use cancellation token which you can pass to Task.Delay - then form don't need to wait for extra second, but can cancel Delay straight away.

Is it possible remove a session variable with a timer?

I want to remove a session variable using a timer. I have this class.
Public Class SessionKiller
Private WithEvents mclsTimer As Timer
Private mstrSessionKey As String
Public Sub New(ByVal lstrSessionKey As String)
mstrSessionKey = lstrSessionKey
mclsTimer = New Timer(3000)
mclsTimer.AutoReset = False
mclsTimer.Start()
End Sub
Private Sub OnTimedEvent(ByVal lobjSource As Object, lclsEvent As ElapsedEventArgs) Handles mclsTimer.Elapsed
HttpContext.Current.Session.Remove(mstrSessionKey)
End Sub
End Class
But the current variable is nothing. Is it possible remove a session variable this way?
I solved using a pointer to session var.
Public Class SessionKiller
Private WithEvents mclsTimer As Timer
Private mstrSessionKey As String
Private mclsSession As HttpSessionStateBase
Public Sub New(ByVal lstrSessionKey As String, _
ByVal lclsSession As HttpSessionStateBase)
mstrSessionKey = lstrSessionKey
mclsSession = lclsSession
mclsTimer = New Timer(3000)
mclsTimer.AutoReset = False
mclsTimer.Start()
End Sub
Private Sub OnTimedEvent(ByVal lobjSource As Object, lclsEvent As ElapsedEventArgs) Handles mclsTimer.Elapsed
mclsSession.Remove(mstrSessionKey)
End Sub
End Class

AddressOf with parameter

One way or another I need to link groupID (and one other integer) to the button I am dynamically adding.. any ideas?
What I can do;
AddHandler mybutton.Click, AddressOf PrintMessage
Private Sub PrintMessage(ByVal sender As System.Object, ByVal e As System.EventArgs)
MessageBox.Show("Dynamic event happened!")
End Sub
What I can't do, but want to;
AddHandler mybutton.Click, AddressOf PrintMessage(groupID)
Private Sub PrintMessage(ByVal groupID as Integer)
MessageBox.Show("Dynamic event happened!" & groupID .tostring)
End Sub
There is no way to do this with AddressOf itself. What you're looking for is a lambda expression.
AddHandler myButton.Click, Function(sender, e) PrintMessage(groupId)
Private Sub PrintMessage(ByVal groupID as Integer)
MessageBox.Show("Dynamic event happened!" & groupID .tostring)
End Sub
You can create your own button class and add anything you want to it
Public Class MyButton
Inherits Button
Private _groupID As Integer
Public Property GroupID() As Integer
Get
Return _groupID
End Get
Set(ByVal value As Integer)
_groupID = value
End Set
End Property
Private _anotherInteger As Integer
Public Property AnotherInteger() As Integer
Get
Return _anotherInteger
End Get
Set(ByVal value As Integer)
_anotherInteger = value
End Set
End Property
End Class
Since VB 2010 you can simply write
Public Class MyButton
Inherits Button
Public Property GroupID As Integer
Public Property AnotherInteger As Integer
End Class
You can access the button by casting the sender
Private Sub PrintMessage(ByVal sender As Object, ByVal e As EventArgs)
Dim btn = DirectCast(sender, MyButton)
MessageBox.Show( _
String.Format("GroupID = {0}, AnotherInteger = {1}", _
btn.GroupID, btn.AnotherInteger))
End Sub
These new properties can even be set in the properties window (under Misc).
The controls defined in the current project automatically appear in the toolbox.
Use the Tag property of the button.
Button1.Tag = someObject
AddressOf gets the address of a method, and thus you cannot pass parameters to it.
You can use delegate which very clear for your code follow as:
Define a delegate
Public Delegate Sub ControlClickDelegate(ByVal sender As Object, ByVal e As EventArgs)
Custom button class
Public Class CustomButton
Inherits System.Windows.Forms.Button
#Region "property delegate"
Private controlClickDelegate As ControlClickDelegate
Public Property ClickHandlerDelegate As ControlClickDelegate
Get
Return controlClickDelegate
End Get
Set(ByVal Value As ControlClickDelegate)
controlClickDelegate = Value
End Set
End Property
#End Region
Public Sub RegisterEventHandler()
AddHandler Me.Click, AddressOf OnClicking
End Sub
Private Sub OnClicking(ByVal sender As Object, e As System.EventArgs)
If (Me.controlClickDelegate IsNot Nothing) Then
Me.controlClickDelegate(sender, e)
End If
End Sub
End Class
MainForm
Public Class MainForm
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.CusButton1.ClickHandlerDelegate = AddressOf Me.btnClick
Me.CusButton1.RegisterEventHandler()
End Sub
Private Sub btnClick(ByVal sender As Object, ByVal e As EventArgs)
Me.TextBox1.Text = "Hello world"
End Sub
End Class
The below worked for me:
Dim bStart = New Button With {.Text = "START"}
AddHandler bStart.Click, Function(sender, e) TriggerProcess(any Long value)
Private Function TriggerProcess(ByVal paramName As Long) As Boolean
' any processing logic
Return True
End Function
My solution:
AddHandler menuItemYear.Items(i).MouseUp, Sub() menu_year(2019)
Private Sub menu_year(ByVal intYear As Integer)
'do something
End Sub
There are few ways to do that depending of the complexity and number of parameters required.
1. Use Tag for adding a complex structure
2. Inherit the the Button class and add the values as class members then populate them before using it. That gives you a lot more flexibility.
If you are using web version
3. You cannot add it to Tag, but for simple values assign it to index use .Attributes.Add("name"). This gets added to the HTML tags and not the Server side. You can then use the index to access a server side structure for complex systems.
4. Use sessions to store values and store the session reference to Name attribute as described above (#3).
No problem ;-)
For example:
Private ComboActionsOnValueChanged As New Dictionary(Of ComboBox, EventHandler)
'somewhere in function
dim del = Sub(theSender, eventArgs)
MsgBox(CType(theSender, ComboBox).Name & " test")
End Sub
ComboActionsOnValueChanged.Add(myCombo, del)
'somewhere else
Dim delTest = ComboActionsOnValueChanged(myCombo)
RemoveHandler myCombo.SelectedValueChanged, delTest
myCombo.DataSource = someDataSource
AddHandler myCombo.SelectedValueChanged, delTest
as we expect, event won't fire after DataSource change in this place

Asynchronous socket library not updating form

I am attempted to write a small asynchronous socket library that I can use to create a client/server application. I can get all of the code to run fine if I leave it in the form, however if I try to move it out into its own class, I cannot figure out how to update the form with connection status, things like that. Below is code, shortened a bit just to make this easier to read and type.
Form Code:
Class Form1
Dim Network as NetworkModule
Public Sub Button1_Click(Sender, e) Handles Button1.Click
Network = New NetworkModule("127.0.0.1", 1234)
End Sub
End Class 'Form1
NetworkModule class:
Class NetworkModule
Private mSocket as Socket
Public Sub New(IP as string, Port as Integer)
Dim remoteEP as New IPEndpoint(IP.Parse(IP), Port)
mSocket = New Socket(internetwork, stream, tcp)
mSocket.BeginConnect(remoteEP, New AsyncCallback(AddressOf onConnect), mSocket)
Notify("Connection to " & remoteEP.ToString) 'This one works
End Sub 'New
Private Sub onConnect(ar as IAsyncResult)
mSocket = CType(ar.AsyncState, Socket)
mSocket.EndConnect(ar)
Notify("Connected") 'This one never shows
End Sub 'onConnect
Private Delegate Sub _Notify(Msg as String)
Private Sub Notify(Msg as String)
If Form1.txtLog.InvokeRequired Then
Form1.txtLog.Invoke(New _Notify(AddressOf Notify), Msg)
Exit Sub
End if
Form1.txtLog.Text &= Msg & vbcrlf
End Sub 'Notify
End Class 'NetworkModule
There is actually more to that class, but I never get anything after the first message goes out. I'm not sure where to go from here. I've tried lots of different methods that I've found on the google searches, some from here, some not. Anybody have any ideas?
Here's how I would rewrite it:
Class Form1
Private Network as NetworkModule
Public NotifyDelegate As NetworkModule.NotifyDelegate
Public Sub New()
NotifyDelegate = New NetworkModule.NotifyDelegate(AddressOf Notify)
End Sub
Public Sub Button1_Click(Sender, e) Handles Button1.Click
Network = New NetworkModule("127.0.0.1", 1234, Me)
End Sub
Public Sub Notify(Msg As String)
txtLog.Text &= Msg & vbCrLf
End Sub
End Class 'Form1
NetworkModule Class (partial):
Class NetworkModule
Public Delegate Sub NotifyDelegate(Msg as String)
Private Sub Notify(Msg as String)
If m_Form.InvokeRequired Then
m_Form.Invoke(Form1.NotifyDelegate, Msg)
Else
m_Form.Notify(Msg)
End If
End Sub 'Notify
Private mSocket as Socket
Private m_Form As Form1
Public Sub New(IP as string, Port as Integer, oForm As Form1)
m_Form = oForm
Dim remoteEP as New IPEndpoint(IP.Parse(IP), Port)
mSocket = New Socket(internetwork, stream, tcp)
mSocket.BeginConnect(remoteEP, New AsyncCallback(AddressOf onConnect), mSocket)
Notify("Connection to " & remoteEP.ToString) 'This one works
End Sub 'New
Update with Interface approach
A better mechanism than passing the form itself is to implement an interface. To do this, first create the interface definition (note that the delegate has moved to the Interface for convenience):
Public Interface INotify
Sub Notify(Msg As String)
Delegate Sub NotifyDelegate(Msg As String)
End Interface
Then Implement the interface in the Form. Note that the form now determines whether or not Invoke is required. This allows the INotify interface to be used in non-UI scenarios, such as logging to disk or the event log.
Public Class Form1
Implements INotify
Public Sub Notify(Msg As String)
txtLog.Text &= Msg & vbCrLf
End Sub
Private Sub INotify_Notify(Msg As String) Implements INotify.Notify
If Me.InvokeRequired Then
Me.Invoke(New INotify.NotifyDelegate(AddressOf Notify), Msg)
Else
Me.Notify(Msg)
End If
End Sub 'Notify
Private Network As NetworkModule
Public Sub Button1_Click(Sender, e) Handles Button1.Click
Network = New NetworkModule("127.0.0.1", 1234, Me)
End Sub
End Class 'Form1
Finally, store a reference to the INotify interface instead of the Form in NetworkModule (note the NetworkModule no longer needs to know or care that an Invoke may be required):
Public Class NetworkModule
Public Delegate Sub NotifyDelegate(Msg As String)
Private m_Notifier As INotify
Private Sub Notify(Msg As String)
m_Notifier.Notify(Msg)
End Sub 'Notify
Public Sub New(IP As String, Port As Integer, oNotifier As INotify)
m_Notifier = oNotifier
' The addition code here
End Sub 'New
End Class

Why is this blocking? (VB.NET multithreading with events and delegates)

I have a feature whereby a class in a dll displays a form asking a user to clear a fault on a printer before clicking a button to say "Retry". The users have been just hitting retry without bothering to clear the fault so I am now coding an interlock:
The button on the invoked form is disabled until a call is made to an 'enable' method on the form.
This is done with delegate invocation as the events triggering these changes come from other dlls running on different threads.
The form's 'enable' method is wired into an EVENT HANDLER handling an event coming in from a different thread (one that monitors an ethernet IO Server).
The problem I have is that THE "_Fault_StateChanged" EVENT NEVER FIRES. I suspected the cause was the "ShowDialog" and "DialogResult" technique I have used here, but I have used this exact same technique elsewhere in this application.
Any suggestions would be great
See code extract below:
MAIN CLASS excerpt
Public Class StatePrintHandler
Private WithEvents _RetryForm As frmRetryReject
Private Delegate Sub delShowRetryDialog()
Private Delegate Sub delResetEnable()
Private Sub InvokeResetEnable()
Dim del As delResetEnable
del = New delResetEnable(AddressOf ResetEnable)
del.Invoke()
End Sub
Private Sub InvokeRetryDialogue()
Dim del As delShowRetryDialog
del = New delShowRetryDialog(AddressOf ShowRetryDialog)
del.Invoke()
End Sub
Private Sub ShowRetryDialog()
_RetryForm = New frmRetryReject
_RetryForm.Prep()
_RetryForm.ShowDialog()
If (_RetryForm.DialogResult = Windows.Forms.DialogResult.OK) Then
Me._RetryForm.Visible = False
End If
End Sub
Private Sub ResetEnable()
If (Not IsNothing(_RetryForm)) Then
_RetryForm.ResetEnable()
Else
AuditTrail("Retry form not active, no action", True)
End If
End Sub
'Event handler for status change coming in on a different thread
Private Sub _Fault_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _fault.StateChanged
If (e.NewState) Then
AuditTrail("Labeller has faulted out during cycling", True)
Else
InvokeResetEnable()
End If
End Sub
End Class
RETRY FORM CLASS excerpt
Public Class frmRetryReject
Private Delegate Sub delEnable()
Public Event Complete()
Public Sub Prep()
Me.OK_Button.Enabled = False
End Sub
Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click
Me.DialogResult = System.Windows.Forms.DialogResult.OK
Me.Close()
End Sub
Public Sub ResetEnable()
If (IsHandleCreated) Then
Dim params() As Object = {}
Me.Invoke(New delEnable(AddressOf InvokeEnable), params)
End If
End Sub
Private Sub InvokeEnable()
Me.OK_Button.Enabled = True
End Sub
End Class
Additional detail in response to Daniel's comments
The code is incomplete here, it's an excerpt. The fault object is a subscription to an external library and is a handler for an ethernet IO server.
The _fault StateChanged event fires when a digital input on an IOServer changes. I know the following:
My trace files show the signal change high, this invokes the retry form.
The signal physically changes low again when the retry screen is still showing.
...but the event does not fire
It's as if the application cannot service the event coming in until the ShowDialog/DialogResult completes - but I am confused about this because I understood that the ShowDialog in .NET 2.0 did not block, I should still be able to service events, and have used this same pattern elsewhere in the app.
A couple of things to note:
The MAIN CLASS is instantiated dynamically at runtime via reflection based on configuration.
This is VS2005 SP2
I will post the entire class in another code box if this helps, but it may crowd the scene...
Thanks
Andy
Imports System.IO
Imports ACS.Interfaces
Imports ACS.Pallet
Public Class StateCimPAKPrintHandler
Inherits StateBase
Private WithEvents _ioManager As ACS.Components.DigitalIOManager
Private _config As StateCimPAKPrintHandlerBootstrap
Private CONST_OutcomeOK As String = "OK"
Private CONST_OutcomeRetry As String = "Retry"
Private CONST_OutcomeException As String = "Exception"
Private WithEvents _busy As ACS.Drivers.Common.InputSignal
Private WithEvents _fault As ACS.Drivers.Common.InputSignal
Private WithEvents _print As ACS.Drivers.Common.OutputSignal
Private WithEvents _palletRelease As ACS.Drivers.Common.OutputSignal
Private _labellingInProgress As Boolean
Private _faulted As Boolean
Private _retryScreenInvoked As Boolean
Private WithEvents _timeout As System.Timers.Timer
Private WithEvents _faultTimer As System.Timers.Timer
Private WithEvents _RetryForm As frmRetryReject
Private Delegate Sub delShowRetryDialog()
Private Delegate Sub delResetEnable()
Private Sub InvokeResetEnable()
Dim del As delResetEnable
del = New delResetEnable(AddressOf ResetEnable)
del.Invoke()
End Sub
Private Sub InvokeRetryDialogue()
Dim del As delShowRetryDialog
del = New delShowRetryDialog(AddressOf ShowRetryDialog)
del.Invoke()
End Sub
Private Sub ShowRetryDialog()
_timeout.Stop()
_retryScreenInvoked = True
_RetryForm = New frmRetryReject
_RetryForm.Prep()
AuditTrail("Displaying Retry screen", True)
_RetryForm.ShowDialog()
If (_RetryForm.DialogResult = Windows.Forms.DialogResult.OK) Then
AuditTrail("User clicked RETRY LINE on the RETRY dialogue", True)
_retryScreenInvoked = False
Me._RetryForm.Visible = False
Me.SetOutcome(CONST_OutcomeRetry)
End If
End Sub
Private Sub ResetEnable()
If (Not IsNothing(_RetryForm)) Then
_RetryForm.ResetEnable()
Else
AuditTrail("Retry form not active, no action", True)
End If
End Sub
Public Sub New(ByVal Sequencer As ISequencer, ByVal ParentPlt As ACS.Interfaces.IPallet, ByVal Name As String)
MyBase.New(Sequencer, ParentPlt, Name)
_timeout = New System.Timers.Timer
_faultTimer = New System.Timers.Timer
_config = New StateCimPAKPrintHandlerBootstrap(Me._myIniFileName, Name)
_timeout.Interval = _config.CycleTimeoutMS
_faultTimer.Interval = 750
_retryScreenInvoked = False
_RetryForm = New frmRetryReject
Me._RetryForm.Visible = False
_ioManager = ACS.Components.DigitalIOManager.GetInstance
_busy = _ioManager.GetInput("Busy")
_fault = _ioManager.GetInput("CimPAKFault")
_print = _ioManager.GetOutput("Print")
_palletRelease = _ioManager.GetOutput("PalletRelease")
End Sub
Public Overrides Sub Kill()
_ioManager = Nothing
_RetryForm = Nothing
_busy = Nothing
_fault = Nothing
_print = Nothing
_timeout = Nothing
_faultTimer = Nothing
_pallet = Nothing
End Sub
Public Overrides Sub Execute()
AuditTrail("Pulsing Print Signal", True)
_print.PulseOutput(3000)
_labellingInProgress = True
_timeout.Start()
End Sub
Private Sub _busy_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _busy.StateChanged
_timeout.Stop()
AuditTrail("Busy signal changed to : " & e.NewState, True)
If (e.NewState) Then
_faulted = False
AuditTrail("CimPAK = Busy High", True)
_labellingInProgress = True
Else
AuditTrail("CimPAK = Busy Low", True)
AuditTrail("Wait 750 milliseconds for any faults", True)
_faultTimer.Start()
End If
End Sub
Private Sub _Fault_StateChanged(ByVal sender As Object, ByVal e As Drivers.Common.DigitalSignalChangedEventArgs) Handles _fault.StateChanged
AuditTrail("Fault signal changed to : " & e.NewState, True)
If (e.NewState) Then
If (_labellingInProgress = True) Then
AuditTrail("Labeller has faulted out during cycling", True)
_faulted = True
If (Not _retryScreenInvoked) Then
InvokeRetryDialogue()
End If
Else
AuditTrail("Labeller has faulted out between cycles, no action can be taken", True)
End If
Else
If (_retryScreenInvoked) Then
AuditTrail("Enable button on Retry screen", True)
InvokeResetEnable()
End If
_faulted = False
End If
End Sub
Private Sub _faultTimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _faultTimer.Elapsed
_faultTimer.Stop()
If (_faulted) Then
AuditTrail("System has faulted", True)
Else
AuditTrail("No fault occured, assume pallet is OK to release", True)
AuditTrail("CimPAK cycle complete", True)
_labellingInProgress = False
_palletRelease.PulseOutput(3000)
Me.SetOutcome(CONST_OutcomeOK)
End If
End Sub
Private Sub _timeout_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _timeout.Elapsed
_timeout.Stop()
AuditTrail("Labeller print cycle timed out", True)
If (Not _retryScreenInvoked) Then
_retryScreenInvoked = True
InvokeRetryDialogue()
InvokeResetEnable()
End If
End Sub
End Class
#Region "Bootstrap"
Public Class StateCimPAKPrintHandlerBootstrap
Private Const CONST_CycleTimeoutMS As String = "CycleTimeoutMS"
Private _CycleTimeoutMS As Long
#Region "Properties"
Public ReadOnly Property CycleTimeoutMS() As Long
Get
Return _CycleTimeoutMS
End Get
End Property
#End Region
Public Sub New(ByVal IniFile As String, ByVal Name As String)
Try
Dim _cfgFile As String = Environ("ACSVAR") & "\" & IniFile
' Check to see if the CFG file exits
If File.Exists(_cfgFile) = False Then
Throw New Exception("Configuration file does not exist: " & _cfgFile)
Else
'Get values
_CycleTimeoutMS = ACS.Utility.Configuration.GetLong(_cfgFile, Name, CONST_CycleTimeoutMS)
End If
Catch ex As Exception
Throw
End Try
End Sub
End Class
#End Region
Try to look at
Visual Basic, Child Thread Blocking Main Thread
answer for in Multithreading example and
New Thread is still blocking UI-Thread
answer from ( me ) for In Model Threading.... Those 2 should give you writen code to start aswell.
It's been a long time since I did any Winforms work, but are you showing the dialog modally? Because that could be the cause of the delegate invokation not arriving.
Asynchronous delegates work by serializing the invokation details into a memory location internal to the framework and then posting a window message to the top-level window for the relevant thread. Modal dialogs work by going into a message processing loop that steals all the messages for the thread so that only that one dialog can respond. You can see how this might conflict.