If you’ve done any GUI programming at all, you’ll have come across a pattern like .NET’s System.ComponentModel.ISynchronizeInvoke. The problem it solves is fairly simple, yet only appears in a multi-threaded environment.
There’s one thread (it’s usually the first one created when the application starts, or at least the one that calls the entrypoint) that is responsible for creating and re-drawing UI controls. It handles messages from the Message Pump, and generally ensures that your UI looks as it should. It’s generally called theĀ GUI Thread.
You can see the actions of the UI thread in Visual Studio. Create a Windows Forms project, and have the eventhandler for a new button throw an Exception. Also, create an event handler for the UnhandledException event on System.AppDomain.CurrentDomain, containing the following code:
MessageBox.Show(((Exception)e.ExceptionObject).StackTrace);
Then just run the app and hit the button. You should see the GUI thread being created, along with a marshal from unmanaged to managed code for the button click. Anyway…
There’s a simple rule: you can only update the UI from the GUI thread. The reason for this is simply explained by example: imagine if you were able to add a list item from one thread, whilst you were moving the window, and the window was being re-drawn from another thread. You’d have half-drawn list items all over the screen, and no consistency in your UI.
The rule is simple, but not usually enforced for performance reasons. Luckily, since .NET 2.0, you’ll get a ThreadAccessException (or similar) when you do this when a debugger’s attached. Back in the bad old days of .NET 1/1.1 you’d sometimes get a Big Red Cross where a control should be. Sometimes you wouldn’t. It’d most often occur once you’d been through UAT and you application was in production.
So what’s the solution? You need to marshal to the GUI thread when you’re not on it, update the control, then get back sharpish. Luckily, System.Windows.Forms.Control implements ISynchronizeInvoke, which provides some stuff that’s interesting to us. This is the bit that most people will be familiar with, but for those that aren’t, here’s the summary:
- bool InvokeRequired { get; } – Gets a value indicating whether the caller must call Invoke when calling an object that implements this interface.
- Object Invoke(delegate method) – Synchronously executes the delegate on the thread that created this object and marshals the call to the creating thread.
Simply put:
protected void Update()
{
if(this.InvokeRequired)
{
this.Invoke(new MethodInvoker(this.Update));
}
else
{
textbox1.Text = "foo"; //whatever
}
}
Yes folks, that’s another nice bit of boilerplate code that you’ve got to put all over your GUI code. Not pretty. But it’s alright, really, because I don’t do that much GUI code – I’m an infreastructure developer. Just kidding – though I did once refer to GUI programming as ‘painting by numbers’, which didn’t go down at all well with some people at work.
Anyhow, long story short: I found this cool thing that lets you use C# 3’s lambdas to describe the work you want to do on the GUI thread.