Tuesday, October 26, 2004: Understanding Chris Sells Teachings about Multi-Threading in Windows Forms: The Importance of Multi-Threading Handlers

Chapter 14 of Chris Sells, his book Windows Forms Programming in Visual Basic .NET (with Justin Gehtland on drums) explains all we need to know about implementing multi-threading designs in all but the most complex Windows Forms. Unfortunately, I had to read this chapter about five times and I had to send several stern emails to Chris Sells (which he generously answered) before I understood these basic bits:

·        Creating a worker thread can be an indirect procedure (by calling BeginInvoke) or it can be a direct procedure by getting a new Threading.Thread object. Sells discuses the disadvantages of using the latter method but I find I am able to name a new Threading.Thread object and sets is priority—I will tentatively call these “advantages.”

·        Think about implementing multi-threading handlers in the same manner you think about implementing error handling: every method that interacts with the UI thread (and is likely to be called from a worker thread) must be designed with a pattern that interrogates the Boolean InvokeRequired for true. The following is the Chris Sells multi-threading handler design pattern (written with my sense of style):

Delegate Sub MySubDelegate(ByRef WinForm As MyNameSpace.MainForm)
Sub MySub(ByRef WinForm As MyNameSpace.MainForm)



    If WinForm.InvokeRequired Then

        Dim del As MySubDelegate _

            = New MySubDelegate(
AddressOf MySub)

        Call WinForm.BeginInvoke(del, New Object() {WinForm})

    Else

        With WinForm

            'TODO: Do stuff to objects on the UI Thread.

        End With

    End If



End Sub
'How will Windows Forms 2.0 eliminate the need for this pattern?

·        When InvokeRequired is always true, the flawed design is probably calling Invoke() or BeginInvoke() from an object created on the worker thread. The design pattern above avoids making this mistake by clearly showing that it is WinForm making the call (there is, believe me, the temptation to use del.BeginInvoke, which is incorrect—it puts wrinkles in Sells’ Burning Man kilt!).

·        Calling back to the UI thread from the worker thread means calling from an object that ultimately derives from System.Windows.Forms.Control that was instantiated by the UI thread.

·        The ISynchronizeInvoke interface contains the aforementioned worker-thread-to-UI-thread method invocations and the Boolean indicator that such an invocation is required. As of this writing, only one class implements this interface System.Windows.Forms.Control. Explaining why the ISynchronizeInvoke interface exists in the first damn place would have gone a long way toward why multi-threading handlers are important.

·        There is the temptation to make all Windows Forms event handlers multi-threading handlers as well. I find that this design goal creates too much code what with the writing of delegates for every single event handler. Another way is to not set form control properties directly in event handlers but to create a Client Layer of static methods that set Windows Forms controls, each with their delegates and multi-threading handlers.

·        When all of the above bits are found to be valid and not addressed by Windows Forms 2.0 kudos to the brilliant author who thunk it all up! Until then, these ideas are all my fault. Sorry, Chris.