InvokeRequired not required
One of the more questionable patterns in .Net Windows Forms programming is the following sort of thing:
private void OnDataChanged(object sender, EventArgs e)
{
if(InvokeRequired)
BeginInvoke(new EventHandler(OnDataChanged), new object[] { sender, e });
else
{
……
}
}
Maybe it’s just me, but having to say “Please do whatever you need to do before you do what I’m about to tell you to do” each and every time I tell someone to do something makes me tired. On a recent project I worked on, we developed a handy strategy to avoid just this.
The key to this solution is the Windows User32 function PostMessage, which will allow you to put a message into the application’s message queue. That message will by definition, wind up received on the GUI thread. All you need is something that will listen, and means for it fire your delegate. A message only window?
Message-Only Windows
A message-only window enables you to send and receive messages. It is not visible, has no z-order, cannot be enumerated, and does not receive broadcast messages. The window simply dispatches messages.
To create a message-only window, specify the HWND_MESSAGE constant or a handle to an existing message-only window in the hWndParent parameter of the CreateWindowEx function. You can also change an existing window to a message-only window by specifying HWND_MESSAGE in the hWndNewParent parameter of the SetParent function.
Our MessageWindow is then wrapped with a queue, to form a Dispatcher, whose job it is to place the delegate to be fired onto the queue and post a message to the MessageWindow, who will take it out and fire it. The last thing we need is some sort of facade or proxy for our original delegate that will allow it be invoked in such a roundabout manner.
The first step is to define an interface that our Dispatcher will use to invoke the the underlying delegate. Let’s call it STAInvoke (for Single Threaded Apartment, the threading model employed by windows forms that made all this necessary in the first place.)
Our DelegateProxy class has the following responsibilities:
— Put messages onto the Dispatcher when invoked.
— Wrap the original delegate and call DynamicInvoke on it once we are in the right thread
— Provide a factory with which you can dispense Delegates derived from proxies
The factory code looks something like this (minus exception handling):
public static Delegate CreateDelegate(Delegate dlgt)
{
DelegateProxy proxy = new DelegateProxy(dlgt,Thread.CurrentThread.ApartmentState == ApartmentState.STA);
Delegate contextdlgt = null;
contextdlgt = Delegate.CreateDelegate(dlgt.GetType(), proxy, “Invoke”);
return contextdlgt;
}
However there is some unpleasantness here. (Let’s call it a long-standing TODO.) The Invoke method on the proxy must have the same signature as your original delegate. Thus for each unique signature in the application with which you would like to use this class, you need an corresponding overload of Invoke in DelegateProxy.
So how do you use this? Let’s say your FooService has a single event, Changed, of type EventHandler. A slight modification of the usual plumbing for attaching events gives you this:
public event EventHander Changed
{
add
{
_changed += (EventHandler)STADelegate.CreateDelegate(value)
}
remove
{
_changed -= (EventHandler)STADelegate.CreateDelegate(value)
}
}
When _changed is fired then, the Invoke method of the DelegateProxy is actually called. This then looks to see if it was orginally created on the GUI thread. If it was not, it simply invokes the original delegate. If it was, it then puts itself onto the queue of the Dispatcher and posts a message into the message queue. When that message is recieved, safely in the GUI thread, the dispatcher removes the DelegateProxy from its queue and calls that DelegateProxy’s STAInvoke method.
If you feel this is a long way to go to replace a little if statement, I (sort of) understand. For me, if(InvokeRequired) BeginInvoke, sounds like some sort of obsessive-compulsive tick, rather than effective use of language. If I’d wanted to have to say things like that all day, I’d have become a lawyer.
SourceCode;
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Lab49.Utils
{
///
///
public class User32
{
///
///
public const int WM_USER= 0×0400;
///
///
public const int HWND_MESSAGE= -3;
///
///
public const int WM_NCCREATE = 0×0081;
///
///
[DllImport("user32.dll")]
public static extern uint RegisterUserMessage(string msgName);
///
///
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint msg, int wP, int lP);
///
///
[DllImport("user32.dll")]
public static extern bool PostThreadMessage(int ThreadID, uint msg, int wP, int lP);
}
public class MessageWindow: NativeWindow, IDisposable
{
public MessageWindow(): this(User32.WM_USER)
{
}
public MessageWindow(uint msg)
{
_msg = msg;
CreateParams createParams = new CreateParams();
createParams.Parent = (IntPtr)User32.HWND_MESSAGE;
base.CreateHandle(createParams);
}
public void Dispose()
{
base.DestroyHandle();
}
public bool Post()
{
return User32.PostMessage(this.Handle, _msg, 0, 0);
}
private uint _msg;
protected virtual void OnMessage() {}
protected override void WndProc(ref Message msg)
{
if(msg.Msg == _msg)
OnMessage();
if(msg.Msg == User32.WM_NCCREATE)
msg.Result = new IntPtr(-1);
}
}
}
More Source Code;
using System;
using System.Threading;
using System.Reflection;
using System.Windows.Forms;
using System.Collections;
namespace Lab49.Utils
{
public class STADelegate
{
static STADelegate()
{
_dispatcher = new Dispatcher();
}
public static Delegate CreateDelegate(Delegate dlgt)
{
DelegateProxy proxy = new DelegateProxy(dlgt, Thread.CurrentThread.ApartmentState == ApartmentState.STA);
Delegate contextdlgt = null;
try
{
contextdlgt = Delegate.CreateDelegate(dlgt.GetType(), proxy, “Invoke”);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}
return contextdlgt;
}
static Dispatcher _dispatcher;
}
public class DelegateProxy: ISTASafeDelegate
{
private Delegate _dlgt;
private static Dispatcher _dispatcher;
private object[] _args;
private bool _isSTA;
static DelegateProxy()
{
_dispatcher = new Dispatcher();
}
public DelegateProxy(Delegate dlgt, bool isSTA)
{
_dlgt = dlgt;
_isSTA = isSTA;
}
public void ContextInvoke()
{
// System.Diagnostics.Debug.WriteLine(“DelegateProxy Invoked from Dispatcher: ” + AsyncDiagnostics.ThreadInfo);
_dlgt.DynamicInvoke(_args);
}
private void Invoke(params object[] args)
{
if(!_isSTA)
ContextInvoke();
_args = args;
_dispatcher.Dispatch(this);
}
private void Invoke(object sender, object[] args)
{
if(!_isSTA)
ContextInvoke();
_args = new Object[]{ sender, args };
_dispatcher.Dispatch(this);
}
private void Invoke(object retVal)
{
if(!_isSTA)
ContextInvoke();
_args = new Object[]{ retVal };
_dispatcher.Dispatch(this);
}
private void Invoke(object sender, EventArgs e)
{
if(!_isSTA)
ContextInvoke();
_args = new object[]{sender, e };
_dispatcher.Dispatch(this);
}
}
public interface ISTASafeDelegate
{
void ContextInvoke();
}
///
///
public class Dispatcher: MessageWindow
{
public Dispatcher()
{
_operations = new Queue();
}
public void Dispatch(ISTASafeDelegate dlgt)
{
lock(_operations.SyncRoot)
{
_operations.Enqueue(dlgt);
}
// System.Diagnostics.Debug.WriteLine(“Dispatching operation to GUI Thread: ” + AsyncDiagnostics.ThreadInfo);
this.Post();
}
protected override void OnMessage()
{
// System.Diagnostics.Debug.WriteLine(“Message Rec’d: ” + AsyncDiagnostics.ThreadInfo);
ISTASafeDelegate dlgt = (ISTASafeDelegate) _operations.Dequeue();
dlgt.ContextInvoke();
}
private Queue _operations;
}
}



July 2nd, 2007 at 10:24 am
That’s so unnecessarily complex that I’m just gobsmacked.
(By the way, I think I might be responsible for originating this pattern – I wrote one of the early articles on this very topic for MSDN. Hi! And although Chris Sells published something very similar earlier than that, he actually based his article on an early draft of mine… So it’s my fault, if indeed there is a fault.)
Did you not realise that Control.BeginInvoke calls PostMessage for you? So you just wrote several pagefuls of code only to reproduce the behaviour you already had at the start with just a handful of code!
Encapsulating this behaviour so that you don’t need to use BeginInvoke explicitly is all very well. But you don’t need to re-implement it!
You started out complaining about the call to InvokeRequried, but then apparently you lost sight of that simple goal. If you want to omit the call to InvokeRequired, then just omit it. It’s only in there to avoid an unnecessary post if you happen already to be on the right thread – it’s essentially an optimization for a specific scenario. If you know you’ll never need that, well just leave it out. And now the first example can be reduced to just a single API call, which is significantly better than what you’ve written!
Of course, with .NET 2.0 and later, if you were going to build this kind of functionality, you’d almost certainly wrap the SynchronizationContext instead. (That also supports WPF, even though that has a slightly different message processing model.)