Tuesday, September 24, 2013

VB.Net Cross Thread Events in WinForms

Today I quickly did a proof of concept on integrating a third part component into a winforms application and had to figure out how to raise events on the Windows Forms UI thread from a different one. There are plenty of examples of doing this in C# but they didn't quite translate to VB.Net.

Although a BackgroundWorker may have worked I had some more complex requirements. Therefore I slightly tweaked a C# cross thread example on stackoverflow and combined it with another example of building a custom event. Here is what I came out with. I have to investigate better ways of doing this but since there is a lack of any VB.Net examples I thought I would post one.

Imports System.ComponentModel
Imports System.Threading

Public Class CrossThreadingExample

    Private dummyThread As Thread

    Private ReadOnly crossThreadEventList As New List(Of CrossThreadEventHandler)

    Public Delegate Sub CrossThreadEventHandler(sender As Object, e As CrossThreadEventArgs)

    Public Custom Event CrossThreadNotification As CrossThreadEventHandler

        AddHandler(handler As CrossThreadEventHandler)
        End AddHandler

        RemoveHandler(handler As CrossThreadEventHandler)
        End RemoveHandler

        RaiseEvent(sender As Object, e As CrossThreadEventArgs)
            For Each del In Me.crossThreadEventList
                Dim synchronizedInvoke As ISynchronizeInvoke = DirectCast(del.Target, ISynchronizeInvoke)

                If synchronizedInvoke IsNot Nothing AndAlso synchronizedInvoke.InvokeRequired Then
                    synchronizedInvoke.Invoke(del, New Object() {sender, e})
                    del.DynamicInvoke(New Object() {sender, e})
                End If

        End RaiseEvent

    End Event

    Public Sub Start()
        Me.dummyThread = New Thread(AddressOf DoWork)
        Me.dummyThread.IsBackground = True
    End Sub

    Public Sub Cancel()
    End Sub

    Private Sub DoWork()
        Dim i As Integer = 0
        While i < Integer.MaxValue
            i += 1
            If i Mod 10 = 0 Then
                RaiseEvent CrossThreadNotification(Me, New CrossThreadEventArgs(i))
            End If

        End While
    End Sub

End Class

Public Class CrossThreadEventArgs
    Inherits EventArgs

    Public Property NumberDivisibleBy10 As Integer

    Public Sub New(number As Integer)
        Me.NumberDivisibleBy10 = number
    End Sub

End Class

And here is an example of using it on a Windows Form where a label gets updated with values divisible by 10.

Public Class ExampleForm

    Private WithEvents crossThreadingExample As CrossThreadingExample

    Public Sub New()
        Me.crossThreadingExample = New CrossThreadingExample()
    End Sub

    Public Sub ChangeLabel(sender As Object, e As CrossThreadEventArgs) Handles crossThreadingExample.CrossThreadNotification
        Me.LabelCounter.Text = e.NumberDivisibleBy10.ToString()
    End Sub

    Protected Overrides Sub OnClosing(e As System.ComponentModel.CancelEventArgs)
    End Sub

End Class

No comments:

Post a Comment