Showing posts with label events. Show all posts
Showing posts with label events. Show all posts

Implementing IEventDispatcher

english mobile

Recently, I had to have a class that took arguments in its constructor and also was able to dispatch events. Rather than trying to extend EventDispatcher and worry about separating the arguments the rest of the class needed from the ones EventDispatcher needed, I decided to implement IEventDispatcher. Problem was, I hadn't done this in a while, and I couldn't remember the right way to do this and had no idea what project had an example of it. So, I went searching on the web and refreshed my memory that you need to include an EventDispatcher instance in your class and route your IEventDispatcher methods through that object.

I created some boilerplate code that I can just cut and paste to add IEventDispatcher support to a class, and I share it with you now.



//--------------Support for IEventDispatcher--------------//


private var _ed:EventDispatcher;

public
function addEventListener(type:String, listener:Function,
useCapture:Boolean=false, priority:int=0,
useWeakReference:Boolean=false):void
{
_ed.addEventListener(type,
listener, useCapture, priority, useWeakReference);
}
public function
removeEventListener(type:String, listener:Function,
useCapture:Boolean=false):void
{
_ed.removeEventListener(type, listener,
useCapture);
}
public function
dispatchEvent(event:Event):Boolean
{
return
_ed.dispatchEvent(event);
}
public function
hasEventListener(type:String):Boolean
{
return
_ed.hasEventListener(type);
}
public function
willTrigger(type:String):Boolean
{
return _ed.willTrigger(type);
}



Enjoy!

Updated 12/15/08:
Note that you'll need to put an instance of EventDispatcher in _ed in the constructor of the class that's implementing IEventDispatcher:

_ed=new EventDispatcher(this);

Updated 12/21/08:
Josh McDonald posted code that shows how to implement IEventDispatcher with boilerplate that doesn't require adding a line to the constructor.

Dispatching Events

english mobile

I'm thinking I'm probably extra stupid, but I kind of got the impression from the Event handling docs that if you wanted to send out your own events, you had to have your own events class. It seemed to me there was something magical in the constants defining event names in your events class that somehow made the events so named "your" events. It turns out that if you want to dispatch an event "this is an event" then it really is as simple as

dispatchEvent(new Event("this is an event"));

Then all you have to do is add an event listener for "this is an event". There's no more magic to it than that. The event just needs to be called the same thing on both sides, and that is what the constants make sure of. But they're not required.

Now, if you want to pass more information in an event, such as whether a click on a Multiple Choice Question is right or wrong, then you'd need your own Event class. But for simply broadcasting an event you know is yours, you just send out an event as above. Duh.

I figure most people reading this are not as "challenged" as I am, but hopefully this helps someone anyway.

Update 7/3/2008: When a component is dispatching events, it should also "announce" what events are available on it with an Event metadata tag, such as [Event (name="thisIsAnEvent" type="flash.events.Event")]. This allows you to use it in MXML without a compiler error. I honestly don't know whether multi-word event name, as stated in my original example, would cause an error or not.

Modules for eLearning

english mobile

I've written before about how difficult I've found it to figure out how to use Modules for eLearning style structures within Flex. It seems to me I may have hit upon an approach that works. The new documentation on Modules has an example that shows creating an Interface so that you have a known "contract" between the Module and the parent container. The example shows how to pass information into the Module, but didn't seem at all concerned about passing information back out. So I put my thinking cap on, and went to researching.

The first thing that seemed obvious to me was that you'd need to have some sort of event that would be propogated from the Module to tell the parent container that something had happened. So, I went and looked at the documentation about how to handle events. And I really, really tried to figure out a way to do it just with the implementation of the functions from the Interface. But functions in an Interface are kinda tricky. They're fairly plain Jane (in the Interface itself they're just stubs, with no implementation) and are really designed to be called from whatever is Interfacing with the Interfacee (as it were). I couldn't figure out a way to use them to push information out with them.

Instead, what I did was create a function that will return the name of the event that the Module expects to send out to the container. This allows the container to attach an event listener for that event without having to know up front what it will be called. So, for instance you could have an ElearningEvent.MENU_CLICK or an ElearningEvent.MC_SELECTION.

Where did the names for these events come from? Well, let me back up. I wrote a custom event class called ElearningEvent, specifically for handling events from my own eLearning Modules. I imported this class both into the Module file and into the Container file. It had public static constants in it that defined the ELearningEvent types. Ultimately, I plan to extend it so that more custom events can convey more information, such as whether a question was right or wrong (right now, it just publishes a value and ID).

So now that I've rambled all over the map, let me distill the process into a nutshell:

  1. First, I wrote the Interface .as file (IELearning.as), which essentially said "these are the functions you can use to access me, and here are the arguments I expect and what I will return."
  2. Next, I wrote the ELearningEvent class, which defined my custom event, including constants covering the event types included in it. I made it Inspectable so that Flex Builder would help with the typing.
  3. I added the implements element to the Module to specify that it implemented IELearning. I added the implementation of the Interface functions, including the one that published the specific event for this Module (in this case, a MENU_CLICK). And I added logic to listen for a click on the menu and generate my ElearningEvent.
  4. In the containing Application, I added logic similar to the logic in the Module docs to retrieve a reference to the Module child when it loaded. The difference is, I also asked for the name of the event that the Module child was planning to generate, and attached an event listener to the child.

The Module file was already inserted into the Application file, and I'd already worked out its base functionality before I started the process above.

I'm still not sure why an Interface is the suggested solution for this. I would think that maybe just writing an ordinary class, might be better, or even a fake abstract class.