BE SOCIAL

Thursday, November 20, 2014

.Net Multithreading

This post is a companion to the video tutorial released on YouTube. It includes complete code used in the sample application featured in the video. You are welcome to copy and paste parts or entire code section. If you have any questions or comments please do not hesitate to leave them at the end of this post.









THE FOLLOWING IS A YouTube VIDEO TUTORIAL PART 1 - 3 





MAIN THREAD FORM SOURCE CODE


Public Class cButtonMThreading
    '************************ THREADED CODING SECTION *************************************
    Private thCChanger As Threading.Thread
    Private bThreadWorking As Boolean = False
    Private bCancelThread As Boolean = False
    Private bSlowDownThread As Boolean = False

    Private Sub StartColorChanger()
        Try
            Dim tmpCChanger As New clsThreaded(AddressOf thUpdate_Remote, AddressOf thCompleted_Remote)
            thCChanger = New Threading.Thread(AddressOf tmpCChanger.Worker)
            thCChanger.Name = "ColorChanger"
            bThreadWorking = True
            bCancelThread = False
            bSlowDownThread = False
            thCChanger.Start()
        Catch ex As Exception
            bThreadWorking = False
            bSlowDownThread = False
        End Try
    End Sub

    'Thread update delegate
    Friend Function thUpdate_Remote(oNewColor As Color) As Integer
        Try
            If InvokeRequired Then
                Dim tDelegate As New clsThreaded._ThreadUpdate(AddressOf thUpdate_Local)
                Return Invoke(tDelegate, oNewColor)
            Else
                Return thUpdate_Local(oNewColor)
            End If
        Catch ex As Exception
            Return clsThreaded.TH_RESULT_FAILED
        End Try
    End Function
    Private Function thUpdate_Local(oNewColor As Color) As Integer
        Try
            Dim iResult As Integer = clsThreaded.TH_RESULT_OTHER
            picHome.BackColor = Color.FromArgb(oNewColor.A, oNewColor.R, oNewColor.G, oNewColor.B)
            If bCancelThread Then
                iResult = clsThreaded.TH_RESULT_CANCELED
            ElseIf bSlowDownThread Then
                iResult = clsThreaded.TH_RESULT_SLOW_DOWN
            Else
                iResult = clsThreaded.TH_RESULT_CONTINUE
            End If
            Return iResult
        Catch ex As Exception
            Return clsThreaded.TH_RESULT_FAILED
        End Try
    End Function
    'Thread complete delegate
    Friend Sub thCompleted_Remote(iResult As Integer, cExMsgs As Generic.List(Of String))
        Try
            If InvokeRequired Then
                Dim tDelegate As New clsThreaded._ThreadCompleted(AddressOf thCompleted_Local)
                Invoke(tDelegate, iResult, cExMsgs)
            Else
                thCompleted_Local(iResult, cExMsgs)
            End If
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
    Friend Sub thCompleted_Local(iResult As Integer, cExMsgs As Generic.List(Of String))
        Try
            bThreadWorking = False
            'Here you might want to process the thread exit variables (iResult and cExMsgs) for state information 
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub

    '* END ******************** THREADED CODING SECTION ************************** END *

    Private Sub lbMsg_Click(sender As System.Object, e As System.EventArgs) Handles lbMsg.Click
        lbMsg.Text = ""
    End Sub

    Private Sub picHome_Click(sender As System.Object, e As System.EventArgs) Handles picHome.Click
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnDemoHome30_MOver
            lbMsg.Text = "HOME BUTTON CLICKED"
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picHome_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles picHome.MouseDown
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnDemoHome30_MClick
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picHome_MouseEnter(sender As Object, e As System.EventArgs) Handles picHome.MouseEnter
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnDemoHome30_MOver
            lbMsg.Text = "MOUSE OVER HOME BUTTON"
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picHome_MouseLeave(sender As Object, e As System.EventArgs) Handles picHome.MouseLeave
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnDemoHome30
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picOK_Click(sender As System.Object, e As System.EventArgs) Handles picOK.Click
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnOK_CheckGreen30_MOver
            lbMsg.Text = "OK BUTTON CLICKED" + vbCrLf + "STARTING CHILD THREAD"
            StartColorChanger()
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picOK_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles picOK.MouseDown
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnOK_CheckGreen30_MClick
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picOK_MouseEnter(sender As Object, e As System.EventArgs) Handles picOK.MouseEnter
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnOK_CheckGreen30_MOver
            lbMsg.Text = "MOUSE OVER OK BUTTON"
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picOK_MouseLeave(sender As Object, e As System.EventArgs) Handles picOK.MouseLeave
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnOK_CheckGreen30
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picCancel_Click(sender As System.Object, e As System.EventArgs) Handles picCancel.Click
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnCancel_XRed30_MOver
            If Not bSlowDownThread Then
                lbMsg.Text = "CANCEL BUTTON CLICKED" + vbCrLf + "SLOW DOWN THE CHILD THREAD"
                bSlowDownThread = True
            ElseIf Not bCancelThread Then
                lbMsg.Text = "CANCEL BUTTON CLICKED" + vbCrLf + "STOP THE CHILD THREAD"
                bCancelThread = True
            Else
                lbMsg.Text = "CANCEL BUTTON CLICKED" + vbCrLf + "RESET THE BUTTON COLOR"
                If (thUpdate_Remote(Color.Transparent)) = clsThreaded.TH_RESULT_FAILED Then
                    MsgBox("Background reset failed.")
                End If
            End If
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picCancel_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles picCancel.MouseDown
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnCancel_XRed30_MClick
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picCancel_MouseEnter(sender As Object, e As System.EventArgs) _
                                                        Handles picCancel.MouseEnter
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnCancel_XRed30_MOver
            lbMsg.Text = "MOUSE OVER CANCEL BUTTON"
        Catch ex As Exception

        End Try
    End Sub

    Private Sub picCancel_MouseLeave(sender As Object, e As System.EventArgs) Handles picCancel.MouseLeave
        Try
            Dim tPic As PictureBox = DirectCast(sender, PictureBox)
            If Not IsNothing(tPic.Image) Then
                tPic.Image.Dispose()
                tPic.Image = Nothing
            End If
            tPic.Image = Global.CustomButton.My.Resources.btnCancel_XRed30
        Catch ex As Exception

        End Try
    End Sub
End Class

CHILD THREAD CLASS SOURCE CODE

Imports System.Drawing
Public Class clsThreaded
    'Public constants (flags) used by both child and parent threads to comunicate during the thread execution
    Public Const TH_RESULT_OTHER As Integer = 0
    Public Const TH_RESULT_FINISHED As Integer = 1
    Public Const TH_RESULT_CANCELED As Integer = 2
    Public Const TH_RESULT_FAILED As Integer = 3
    Public Const TH_RESULT_CONTINUE As Integer = 4
    Public Const TH_RESULT_SLOW_DOWN As Integer = 5

    'Delegate declaration (blueprint)
    Public Delegate Sub _ThreadCompleted(ByVal iResult As Integer, ByVal sErrorMsgs As Generic.List(Of String))

    'A child thread local procedure based on the delegate declaration
    Private ThCompleted As _ThreadCompleted

    'Delegate declaration (blueprint)
    Public Delegate Function _ThreadUpdate(cNColor As Color) As Integer

    'A child thread local procedure based on the delegate declaration
    Private ThUpdate As _ThreadUpdate

    'Local variables
    Private cLastColor As Color
    Private cMsg As Generic.List(Of String)

    'Sub New - used to initialize local variables and map the call back procedures to the procedures in the parent thread 
    'sub arguments are pointers (AddressOf) to the procedures in the main thread
    Public Sub New(cbThUpdate As _ThreadUpdate, cbThCompleted As _ThreadCompleted)
        Try
            ThCompleted = cbThCompleted
            ThUpdate = cbThUpdate
            'Initialize to pure Red
            cLastColor = Color.FromArgb(255, 255, 0, 0)
            cMsg = New Generic.List(Of String)
        Catch ex As Exception

        End Try
    End Sub
    'Main working procedure
    Public Sub Worker()
        Try
            Dim bUp As Boolean = True
            Dim iGreenBlue As Integer = 0
            Dim iState As Integer = TH_RESULT_CONTINUE

            While iState = TH_RESULT_CONTINUE Or iState = TH_RESULT_SLOW_DOWN
                Dim cNewColor As New Color
                'Calculate new color values
                If iGreenBlue + 5 > 255 Then
                    bUp = False
                ElseIf iGreenBlue - 5 < 0 Then
                    bUp = True
                End If
                Select Case bUp
                    Case True
                        iGreenBlue += 5
                    Case Else
                        iGreenBlue -= 5
                End Select
                'Double check if the color is valid
                If iGreenBlue > 255 Then
                    iGreenBlue = 255
                ElseIf iGreenBlue < 0 Then
                    iGreenBlue = 0
                End If
                'Create new color that will be send to the main thread
                cNewColor = Color.FromArgb(255, 255, iGreenBlue, iGreenBlue)
                'Check SlowDown flag
                If iState = TH_RESULT_SLOW_DOWN Then Threading.Thread.Sleep(50)
                'Send the new color to the main thread
                iState = ThUpdate(cNewColor)
            End While
            ThCompleted(iState, cMsg)
        Catch ex As Exception
            cMsg.Add(ex.Message)
            ThCompleted(TH_RESULT_FAILED, cMsg)
        End Try
    End Sub
End Class


No comments:

Post a Comment