first_page

Old Channel 9 Post

Note: The following was first posted on Channel 9 in October of 2004. I’m posting it here because it’s faster to search for it on my Blog than on Channel 9, its cast of tens of thousands. This post did not please Chris because he interpreted my tone as an angry critique of his work. Carl Franklin evidently does the same shit. I will chalk all this misinterpretation up to my years in the ghettos of Los Angeles that did not refine my pleasure-giving skills to colleagues. I will be attending several classes at a charm school held at the University of the Bubonic Plague in Lynchburg Virginia.

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 explaining 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.

rasx()