Hooking dispatchEvent for Cairngorm Events

| No Comments | No TrackBacks

Gone are the days of cairngormEvent.dispatch(); and CairngormEventDispatcher.getInstance().dispatchEvent( cairngormEvent );. Say hello to dispatchEvent( cairngormEvent );!

A downside of using Cairngorm is that you need to remember that Cairngorm events are "special". Because of how the controller registers listeners, you need to dispatch Cairngorm events through the CairngormEventDispatcher instance in order for the associated commands to execute. Self-dispatching events were added in Cairngorm 2.2 to make things a little easier, but that addition still doesn't address the fact that these events are "different" from other events:

public function doLogin():void
{
	var event:LoginEvent = new LoginEvent( username.text, password.text );
	// Dispatch through the dispatcher directly
	CairngormEventDispatcher.getInstance().dispatchEvent( event );
	// Or, have the event dispatch itself using Cairngorm 2.2+
	event.dispatch();
}

A better approach, I think, is to remove the "special"-ness of Cairngorm events and treat them the same as any other regular event. Rather than having to remember that Cairngorm events get dispatched a special way, doesn't it make sense to simply use the standard dispatchEvent function?

In order to accomplish this, we need to abstract the Cairngorm event dispatching logic further up the chain. We still need to to dispatch Cairngorm events through the CairngormEventDispatcher instance, but we can create an abstraction that allows us to not have to know this extra information. This abstraction allows us to treat Cairngorm events as regular events and just dispatchEvent() them.

So how do we create this abstraction? Simple. We hook dispatchEvent at the UIComponent level. Example code after the jump.

/** Create the dispatch event hook when the Application is created. */
private static dispatchEventHooked:Boolean = hookDispatchEvent();

/**
 * Add a hook into dispatchEvent high up in the inheritance chain.  Any
 * subclass of UIComponent is now "CairngormEvent-aware" and no longer
 * needs separate event dispatching code for Cairngorm events.
 */
private static function hookDispatchEvent():Boolean
{
	UIComponent.mx_internal::dispatchEventHook = cairngormDispatchEventHook;

	return true;
}

/**
 * The event hook itself.  Any time we encounter a CairngormEvent, we
 * dispatch it through the centralized CairngormEventDispatcher.  This
 * abstraction prevents subclasses from having to know how to deal with
 * Cairngorm events.
 */
private static function cairngormDispatchEventHook( event:Event, uic:UIComponent ):void
{
	if ( event is CairngormEvent )
	{
		CairngormEventDispatcher.getInstance().dispatchEvent( event as CairngormEvent );
	}
}

The beauty of this approach is that it allows you to use dispatchEvent( cairngormEvent ) from any view in your application. This includes nested child views, popup windows, etc. Additionally, it doesn't interfere with regular events and normal event dispatching. The hook simply allows some code to be run before the regular dispatchEvent is called. Cairngorm events make it to the controller via the hook, and regular events still get dispatched as normal.

That said, there are a few downsides to this technique.

  • Since the dispatchEventHook function is scoped as mx_internal, the usual caveats apply (e.g. it may be removed in future versions, etc.)
  • I couldn't find any documentation on dispatchEventHook in UIComponent or anywhere online for that matter. In fact, it was by complete accident that I even stumbled across it in the first place. I've searched the Flex SDK code (both versions 2 and 3) to see if it's in use but I couldn't find any references to it. It seems to not be in use for now, but naturally, this is subject to change in the future.
  • Since the hook itself is a reference to a function, it can easily be overwritten somewhere else without you knowing it. So far I haven't found this to be the case, but you never know...
  • A side effect here is that even though Cairngorm events get dispatched correctly through the CairngormEventDispatcher instance, the regular dispatchEvent() is called on the event instance as well. I haven't found this to be a problem, but it's something to be aware of. You might need to manually stop the propagation of the event in the hook if you run into issues.

That said, I've been using this on my current project without any issues to speak of so far. It's been great to have a consistent event dispatching mechanism, and finally cleans up one of the "messy" aspects of Cairngorm.

No TrackBacks

TrackBack URL: http://www.darronschall.com/mt/mt-tb.cgi/154

Leave a comment

Flex.org - The Directory for Flex

Archives