Archive
Learning Employee Directory 5.2 event clone
Return to table of contents
ED’s custom events don’t override the clone() method: it doesn’t need because the events are never redispatched. When I test one of my applications I kept getting the following error:
Error #1034: Type Coercion failed: cannot convert flash.events::Event@141cb29 to org.mymvc.MyMVCEvent
It took me quite a while to debug and finally I have to google it. It seems I am not the only one who has the same problem. The trick here is you will have to override the clone() method in your custom events.
And here is a useful link:
http://www.asserttrue.com/articles/2006/10/14/custom-events-in-actionscript-3-0
mymvc: Adobe AIR (Flex) application framework
update:
Checkout MyMVC official website.
—-
I find software architecture is quite an interesting topic as I am learning it. A program is like an organization — how to assemble units such that the entire program is “good”? By “good” I mean it is easy to maintain and flexible to add more functions.
Maybe we can learn something from the organization of neural cells (or neurons) in our brain — after all, Nature is much better than us in organization. There are 3 facts about neurons and their communication:
- A neuron receives messages (through neurotransmitters), does some internal computation, then output some messages (through wires and neurotransmitters);
- When a neuron receives a message, it doesn’t care who sent the message and how the message was sent; When a neuron output a message, it doesn’t care who will receive it or how his message will be used;
- Neurons mostly communicate with neurons nearby; they make long distance communications very sparsely;
Here is a diagram of a neuron:

Translate to language in software engineering, we see
- A unit in a program receives events, do something, then dispatch events;
- A unit doesn’t care where the event comes or where the event will go;
- A unit should not communicate with another “long distance” unit.
Basically, each unit should be as local as possible (i.e., should not depend on other units).
What are units in a program? A component in View, a command, a manager are all units. So in the terminology of MVC (Model/View/Control),
- Controller interprets and handles all events, and call worker classes (commands).
- When a component in View dispatches an event, that event should not contain information from other components. For example, if a login button is clicked, this button can dispatch an event saying “i’m clicked”; the button should not dispatch an event saying “I’m clicked, and the username is xxx and password is yyy”. This is because the button should not depend on other components (such as username TextInput). It’s up to the root of View or the controller to interpret how to act with the “I’m clicked” event.
- Worker classes (commands) should dispatch events (progress, complete and error). Two worker classes can be concatenated to form a sequence worker class, assuming the output message of the first class and the input message of the second class are compatible.

(About event. As different events may use same name (event.type), also as broadcast/tune mode is used, it is sometimes confusing for a controller to tell who and what method dispatches the event. For example, two buttons of very different functions may both dispatch events of the same name ‘CLICKED’. When the controller hears ‘CLICKED’, it has to decide which one is clicked. Or when the controller hears ‘COMPLETE’ event, he has to decide who completes what. He can’t use event.target to determine the dispatcher as usually this event is dispatched by a common broadcast system (RadioStation). So when an event is dispatched, the event should have two more properties, who and what, for clarifications. This modification makes it very easy for multiple developers to write different components as they don’t have to worry if their event name is used.)
Cairngorm is a very nice framework and so I modified Cairngorm and add features I talked above. To avoid confusion, I rename the framework to mymvc.
Main change:
- Front controller can register a sequence of commands again an event
- Front controller can listen events and dispatch events
- Commands have to dispatch complete or error (or progress) event by notifyComplete, notifyError or notifyProgress
- Event has who and what properties, indicating the object and function which dispatch the event.
To illustrate the whole process, consider the following login and get friends list example. I first need clarify that there are two ways to dispatch events: (1) dispatchEvent(e:MyMVCEvent), a regular way where event dispatched by an object and bubble to its parents (chain mode); (2) MyMVCEvent.broadcast(), broadcast with a central radio station and anyone who access the radio station (especially front controller) can hear it (broadcast mode).
Now the example:
A user clicks ‘Log in and Get your friends’ button. This button dispatch ‘LOGIN_BUTTON_CLICKED’ event and bubbles it (chain mode, front controller can’t hear this event). The root of user interface receives this event and get the username and password, and broadcast this ”LOGIN_BUTTON_CLICKED” event with the login information (front controller can hear it).
Front controller then register a sequence command ([LoginCommand, DisplayFriendsCommand]) to handle this event. The LoginCommand creates a delegate to talk to the server and hands the results (login status and user’s friends list) to LoginCommand. Then LoginCommand sends out complete event together with the result (friends list). The DisplayFriendsCommand hears this complete event and update the data in ModelLocator. As the user interface is bound to ModelLocator, the friends list is displayed.
If there is error in the middle (either connection error or wrong password), LoginCommand will broadcast this error event which can be heard by front controller. Then front controller decides what to do (in this case, alert the user the error).
Here is a diagram of the flow:

Here is the code for controller. You can see from line 25 that it can register a sequence of commands.
// in controller
package com.TestMyMVCService.control
{
import com.TestMyMVCService.commands.*;
import com.TestMyMVCService.model.ModelLocator;
import flash.utils.getQualifiedClassName;
import flash.display.Stage;
import mx.controls.Alert;
import org.mymvc.*;
public class Controller extends MyMVCController
{
public function Controller()
{
super();
initialize();
}
private function initialize():void
{
// you can associate an event with a single command
this.addCommand('LENGTHY_BUTTON_CLICKED', DoLengthyCommand);
// or you can associate an event with a sequence command
this.addCommands('LOGIN_BUTTON_CLICKED', [LoginCommand, DisplayFriendsCommand]);
this.addEventListener(MyMVCEvent.ERROR, onError);
this.addEventListener(MyMVCEvent.COMPLETE, onComplete);
this.addEventListener(MyMVCEvent.PROGRESS, onProgress);
}
private function onError(e:MyMVCEvent):void
{
Alert.show(e.data.message);
}
private function onComplete(e:MyMVCEvent):void
{
var nameParts : Array;
var className : String = '';
if(e.who is Array)
{
var ii:int;
for(ii=0; ii<e.who.length; ii++)
{
nameParts = getQualifiedClassName( e.who[ii] ).split("::");
className = className + ',' + nameParts[ nameParts.length - 1 ];
}
Alert.show("controller: I hear complete from sequence command: " + className);
}
else
{
nameParts = getQualifiedClassName( e.who ).split("::");
className = nameParts[ nameParts.length - 1 ];
Alert.show("controller: I hear complete from command: " + className);
}
}
private function onProgress(e:MyMVCEvent):void
{
var root = ModelLocator.getInstance().root;
root.progressPanel.progressbar.setProgress(e.data.progress,100);
root.progressPanel.progressbar.label = e.data.progressMessage;
}
}
}
Here is a source code (outdated, please refer to MyMVC official website)
MyMVC Library
The Example
And here are the file structure. The server-related files are simply Cairngorm files, the files in the red box are mymvc specific files.


Learning Employee Directory 5. Events
Return to table of contents
ED defines 4 custom events,
CommandCompleteEvent
CommandProgressEvent
DataSynchronizationEvent
SelectedItemChangeEvent
The main job of these custom events seems to define constant (say public static const COMPLETE : String = “complete”;). Although CommandCompleteEvent and CommandProgressEvent also include a variable “command” which stores the command which dispatch the event, I don’t see ED uses this information (Except in CommandProgressEvent, this Event can retrieve the progress and progressMessage of the corresponding command).
The only class which dispatches SelectedItemChangeEvent is ApplicationModel. The only place where this event is listened is MainContentContainer. Although SelectedItemChangeEvent has variable “item”, again it seems not to be used. ApplicationModel holds a copy of “item” and it is this copy that is used.
Learning Employee Directory 2.2 Commands
Return to table of contents
All command classes are inherited from class Command. By name, commands perform something. Every command has execute() which does the job, and emits progress and complete event, and possibly error event.
The base class, Command, has the following three main functions:
public function execute() : void protected function notifyComplete() : void protected function notifyProgress( progress:uint, progressMessage:String = null ) : void protected function notifyError( msg:String ) : void
The execute() function has to be overridden and implemented by subclasses. Other functions in a command class are usually private — this makes perfect sense as commands are supposed to execute only.
When using (or calling) a command, ED usually does this (using InitApplicationCommand as an example):
var cmd : InitApplicationCommand = new InitApplicationCommand( stage ); cmd.addEventListener( CommandCompleteEvent.COMPLETE, onAppInitComplete ); cmd.addEventListener( CommandProgressEvent.PROGRESS, onAppInitProgress ); cmd.addEventListener( ErrorEvent.ERROR, onAppInitError ); cmd.execute();
You will find this pattern again and again in ED.
Learning Employee Directory 3.3 Component
Return to table of contents
1. CustomAutoComplete
This component can be very useful. It pops up a list of suggestions based on characters entered by the user. This is a very simple example on how to use it:
<controls:CustomAutoComplete id="searchInput"
typedTextChange="onTextChange();"
selectionChange="onSelectionChange();"
dataProvider="{ searchResults }"
lookAhead="true"
labelField="displayName"/>
And below is the the script part of the main mxml file I used to test this component.
import mx.controls.Alert;
import mx.collections.ArrayCollection;
[Bindable]
private var searchResults:ArrayCollection = new ArrayCollection();
private var all:ArrayCollection = new ArrayCollection();
private function init():void
{
all.addItem({displayName:"abc", name:"Jack Smith"});
all.addItem({displayName:"abd", name:"John Win"});
all.addItem({displayName:"abe", name:"Bob XC"});
all.addItem({displayName:"acd", name:"LIN Bobby"});
all.addItem({displayName:"efg", name:"xie iix"});
all.addItem({displayName:"efv", name:"xfe abc"});
all.addItem({displayName:"hik", name:"45 65"});
}
private function onTextChange():void
{
searchResults.removeAll();
var ii:int;
for(ii=0;ii<all.length;ii++)
{
if (all[ii].displayName.indexOf(searchInput.typedText) != -1)
searchResults.addItem(all[ii]);
}
}
private function onSelectionChange():void
{
mx.controls.Alert.show(searchInput.selectedItem.name);
}
Learning Employee Directory 4. Flow
Return to table of contents
After the application is initialized, Event “applicationComplete” is dispatched and the following function is called:
// in employeedirectory.mxml ui.init();
Go to ApplicationUI.mxml, we find ui.init() issues the InitApplicationCommand. The process can be shown in the following diagram:

Learning Employee Directory 5.1 Event bubble
Return to table of contents
In ApplicationUI.mxml (init()), you will find the following two lines:
// in ApplicationUI.mxml, in init() titleControls.addEventListener( "showHelp", showHelpScreen ); addEventListener( "close", closePanel );
This is a little bit strange. One uses titleControls as event listener, the other uses ApplicationUI. It turns out this is due to the bubbling of event.
// in TitleControls.mxml
<mx:Button click="dispatchEvent( new Event('showHelp') )" />
// in EmployeeView.mxml <mx:Button id="closeBtn" click="dispatchEvent( new Event( Event.CLOSE, true ) )"/>
Note that the “true” argument in the second case. It allows the Event to bubble to the parent components (ApplicationUI). That’s why ApplicationUI can hear the event. If you add “true” argument in the TitleControls.mxml, you can also use ApplicationUI to listen to the event.
Learning Employee Directory 3.2 Size
Return to table of contents
Which line(s) in the code determines the size of the application?
This seemingly simple question did take me some time. The answer lines in the following two lines:
// in ApplicationUI.mxml <mx:vbox id="contentBox" minwidth="310" minheight="70">
// in MainContentContainer.mxml <mx:canvas width="290">
To really see the effect of changing these values, you need to change the width and height in employeedirectory.mxml. I changed them to 640×800.
// in employeedirectory.mxml <mx:application height="800" width="640" x="100" y="50">
<transparent>false</transparent>
Learning Employee Directory 2.1 Singleton pattern
Return to table of contents
While reading ED code, I frequently encounter singleton pattern. A singleton class is a class you can only instantiate once and it is useful to store application-wide data (say window position). ApplicationModel and all managers are singleton classes.
Here is ED’s approach to singleton class to avoid multiple instantiation:
public class ApplicationModel extends EventDispatcher
{
private static var instance : ApplicationModel;
/**
* Private constructor. Use getInstance() instead.
*/
public function ApplicationModel()
{
if ( instance != null )
{
throw new Error("Private constructor. Use getIntance() instead.");
}
}
/**
* Get an instance of the DataManager.
*/
public static function getInstance() : ApplicationModel
{
if ( instance == null )
{
instance = new ApplicationModel();
}
return instance;
}
}
One will have to use ApplicationModel.getInstance(), instead of new ApplicationModel() to create an ApplicationModel object. Please note the use of “static” in the declaration of variable instance and function getInstance().
In ED, all managers are singleton classes — there is no need to have two managers of the same kind.
There are 4 managers: ConfigManager, DatabaseConnectionManager, DataSynchronizationManager and WindowPositionManager.
ConfigManager: Read employeedirectory_config.xml and get the value of configuration such as data location.
DatabaseConnectionManager: keep the SQLConnection instance.
DataSynchronizationManager: sychronization data
WindowPositionManager: keep the entire window inside the computer screen.





