Imports System.Threading
Public Class Counter
'Incase we need to update anything on the UI
'we use this control to invoke events
'on the UI thread
Private g_objCtl As Control
Private g_thrdInternalBeginCount As Thread
Public Event CountChanged As EventHandler(Of CountChangedEventArgs)
Public Event CountCompleted As EventHandler
Protected Overridable Sub OnCountChanged(ByVal e As CountChangedEventArgs)
RaiseEvent CountChanged(Me, e)
End Sub
Protected Overridable Sub OnCountCompleted()
RaiseEvent CountCompleted(Me, New EventArgs)
End Sub
Public Sub BeginCountAsync(ByVal max As Integer, ByVal delay As Integer)
'Only one instance of the asyncronous counting is allowed
If g_thrdInternalBeginCount IsNot Nothing AndAlso g_thrdInternalBeginCount.IsAlive Then
Throw New NotSupportedException("BeginCount already running")
End If
'Create the control on the thread that called this function
'so we can use the control to invoke on said thread
InitThreading()
g_thrdInternalBeginCount = New Thread(AddressOf InternalBeginCount)
'Ensures that this thread terminates
'when the application terminates
g_thrdInternalBeginCount.IsBackground = True
g_thrdInternalBeginCount.Start(New InternalBeginCountArgs With {.Delay = delay, .Max = max})
End Sub
Public Sub BeginCount(ByVal max As Integer, ByVal delay As Integer)
InternalBeginCount(max, delay)
End Sub
'Thread.Start is only able to take 1 parameter so we must
'package the parameters in an object
Private Sub InternalBeginCount(ByVal args As InternalBeginCountArgs)
InternalBeginCount(args.Max, args.Delay)
End Sub
Private Sub InternalBeginCount(ByVal Max As Integer, ByVal Delay As Integer)
For i = 1 To Max
'If this function was called on a different thread
'from the thread the control was created on
'then we need to invoke it on the control's thread
If g_objCtl.InvokeRequired Then
g_objCtl.Invoke(New Action(Of CountChangedEventArgs)(AddressOf OnCountChanged), New CountChangedEventArgs(i, Max))
Else
OnCountChanged(New CountChangedEventArgs(i, Max))
End If
thread.sleep(Delay)
Next
If g_objCtl.InvokeRequired Then
g_objCtl.Invoke(New Action(AddressOf OnCountCompleted))
Else
OnCountCompleted()
End If
End Sub
Private Sub InitThreading()
If g_objCtl IsNot Nothing Then g_objCtl.Dispose()
g_objCtl = New Control
'Force creation of handle on current thread
Dim x As IntPtr = g_objCtl.Handle
End Sub
Private Class InternalBeginCountArgs
Public Max As Integer
Public Delay As Integer
End Class
End Class
Public Class CountChangedEventArgs
Inherits EventArgs
Private _iMax As Integer
Private _iCurCount As Integer
Public Sub New(ByVal curCount As Integer, ByVal max As Integer)
_iMax = max
_iCurCount = curCount
End Sub
Public ReadOnly Property CurCount() As Integer
Get
Return _iCurCount
End Get
End Property
Public ReadOnly Property Max() As Integer
Get
Return _iMax
End Get
End Property
End Class