Tag Archives: Events

Lazy, Asynchronous Binding, or Call Once, Return Twice

The best part of binding is that it just works: your visible control (the target) gets the data (the source) to show without worrying about synchronizing it with the various steps of data retrieval.

“Getting the value” means retrieving a field, function, or accessor of an object. The target will always get the value when it is initialized in the Configuration phase (so const values work as binding sources even without the [Bindable] metatag).

The Bindable Mantra

“Hear the event, get the value”

The important and subtle implication of this is that the notification dispatcher and the (presumably changed) data are not necessarily the same thing. The normal and default behavior is that changing a value will dispatch an event to the targets bound to that value. This is the built-in behavior when properties use the [Bindable] metatag without specifying an event type; the compiler creates hidden accessors and mutators that checks for changed values (optimizing by ignoring new values that are the same as the old value) and dispatches a PROPERTY_CHANGED event.

The things that bind to the bindable property get a hidden event listener that listens for the PROPERTY_CHANGED event and assigns the source to the target whenever the listener gets an event.

Simple Binding

Target Object: a form

<Application />
    <s:List dataProvider="{foo.listData}" />
</Application>

Source Object: a data class (e.g. a model)

class Foo extends EventDispatcher
{
    [Bindable]
    public var listData : ICollection;
}

Specified Event Binding:[Bindable("foo")]

If the [Bindable] metatag specifies an event type (e.g [Bindable("event type")], then the compiler does not create hidden accessors and mutators for the property; the class must dispatch a notification event itself. One can use this to make non-accessor functions bindable: the hidden event listeners created for the targets will call the function whenever they hear the event and assign the result to the target.

A class can have many properties marked as [Bindable("foo")], and whenever it dispatches new Event("foo"), everything bound to any of those properties will retrieve the data value immediately.

Target Object: a form

<Application />
<!--   call get listData() on initialization and whenever "listDataChange" heard  -->
    <s:List dataProvider="{foo.listData}" />

<!--   call get listCount() on initialization and whenever "listDataChange" heard  -->
    <s:Label text="{foo.getListCount().toString()}" />   
</Application>

Source Object: a data class (e.g. a model)

class Foo extends EventDispatcher
{
    public static const LIST_DATA_CHANGE : String = "listDataChange";
    public static const TOTAL_COUNT_CHANGE : String = "totalCountChange";

    [Bindable("listDataChange")]
    public function get listData() : ICollection
    {
        return _listData;
    }

    public function setListData(value : ICollection) : void
    {
        if (_listData != value)
        {
            _listData = value;
            dispatchEvent(new Event(LIST_DATA_CHANGE));
        }
    }

    [Bindable("listDataChange")]
    public function getListCount() : int
    {
        if (_listData == null)
            return 0;
        else
            return _listData.length;
    }

    [Bindable("listDataChange")]
    [Bindable("totalCountChange")]    // something else dispatches this event
    public function totalCount() : int
    {
        return getListCount() + someOtherNumber;
    }
}

The Cool Bit

Because the notification can be separate from the actual data, one can return result asynchronously to a bound listener. This might be called the Data Accessor Object Pattern.

1. The target calls the source accessor
2. If the underlying object is uninitialized or stale

a. The accessor immediately returns null(which is a perfectly reasonable return value)

b. The accessor sends a request to a server

c. When the server returns data, the responder dispatches the binding event

d. The target hears the binding event and calls the accessor

3. The accessor returns the new data

Target Object: a form

<Application />
 <!--  call get listData() on initialization and whenever "listDataChange" heard -->
    <s:List dataProvider="{foo.listData}" />  
</Application>

Source Object: a data class (e.g. a model)

class Foo extends EventDispatcher
{
    public static const LIST_DATA_CHANGE : String = "listDataChange";

    [Bindable("listDataChange")]
    public function get listData() : ICollection
    {
        if (_listData == null)
        {
            var serverCall = new ServerCall(receiveListData);

            //  return null immediately; don't wait for the server
        }

        return _listData;
    }

    public function receiveListData(data : ICollection) : void
    {
        if (_listData != data)
        {
            _listData = data;

                     // make the bound targets call listData() AGAIN
            dispatchEvent(new Event(LIST_DATA_CHANGE));
        }
    }
}

All AIR Applications Are Single-Instance

This is not an option: if one tries to launch an AIR application twice, the first instance remains and no other instances start. The first application, however, does get notification and the command-line arguments of the subsequent application executions. It’s a subtle way of communicating with a running AIR application.

If an application has to handle multiple instanciation (like a registered file reader), it has to be able to present multiple instances of some part of its user interface (or be willing to replace the current data at any time). This hearkens back to the days of Multi-Document Interface (MDI) applications. One can encapsulate the main UI as a component, and the application can create one for each “instance” the application needs to present.

Multiple Invocations of an AIR ApplicationThe NativeWindow.invoke Event Fires On Every Application Launch

The application will get an event every time the OS launches an instance of the application. It gets an event on startup, and it gets one each time the OS executes the AIR application file; subsequent executions do not start additional  instances. These events contains the command-line parameters specific to that invocation.

The Invoke event fits into the startup cycle here:

  1. FlexEvent.ADD for the application object
  2. FlexEvent.PREINITIALIZE
  3. Event.ADDED for the descendents of the application object
    (These events happen sporadically intermixed with the following events)
  4. FlexEvent.INITIALIZE
  5. FlexEvent.CREATION_COMPLETE
  6. Event.ADDED_TO_STAGE
  7. FlexEvent.APPLICATION_COMPLETE
  8. InvokeEvent.INVOKE
  9. Event.ACTIVATE

Command-line Parameters in AIR Applications

First, the simple behavior:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    invoke="onInvoke(event)">
    <fx:Script>
        <![CDATA[
            private function onInvoke(event : InvokeEvent) : void
            {
                logText.text += "invoke: event.arguments = " + 
                    event.arguments.toString();

                if (event.currentDirectory != null) {
                    logText.text += "; event.currentDirectory = " + 
                        event.currentDirectory.nativePath;
                }
                else
                    logText.text += "; event.currentDirectory = null";


                if (event.reason != null)
                    logText.text += "; event.reason = " + event.reason;
                else
                    logText.text += "; event.reason =  null";
            }
        ]]>
    </fx:Script>

    <s:TextArea id="logText" left="10" right="10" top="105" bottom="10" />
</s:WindowedApplication>

 

Things My Event Told Me

  • InvokeEvent.arguments is an array (never null) of strings. See your operating system for the rules about special characters and quoting.
  • InvokeEvent.currentDirectory is a File instance set to the directory of the executable. Note that running from the IDE will point to the FlashBuilder.exe directory; running from a shortcut/alias will indicate the location of the shortcut, not the .air file.
  • InvokeEvent.reason is either “standard” or “login” if the  OS starts it automatically (see InvokeEventReason for constants)

Things My Event Never Told Me

  • The event does not indicate if this event is part of the application startup (i.e. the first event) or a subsequent invocation. Use a global counter.
  • The event does not indicate if this event is because the OS registered this application for a file type and the user “opened” a file of that type. The sole argument is the complete (native) path including file name, but shortcuts and the command-line can start the application can have a single argument that is a file path as well.

 

Advanced Topics Using a Message-Based Checkbox List Pattern

Fifth in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

The checkbox pattern described in the previous four blog entries allows a lot of flexibility and subtly in your applications. This post covers some of the issues I’ve dealt with, a bit of philosophical and aesthetic musing, and an example application.

Setting The Manager’s Event Listeners

Setting the  list manager’s listeners in the startup event cycle is tricky. In general, I use addEventListener() in the creationComplete event for listeners on the form, however this does not work if the checkbox list or grid is a design-time  child on the form (e.g. it’s in the MXML or created by createChildren()). By the time the creationComplete event fires, the grid has already initialized and all the item renderers have dispatched their first AmISelected events, which receive no answers because the listener is not set up yet.

Register amISelected listeners in the initialized event.

Messages vs. Interfaces

A different way of loosely linking parts of a system is interfaces. One could pass an instance of an interface that had toggleSection and amISelected methods to an item renderer. The class of that instance could be anything; the caller would not know who was executing the method and the method would not know who was calling it. Passing an instance more than one layer deep, however, creates a loosely-linked chain, and the more links in a chain, the more fragile it is.

Every container between the list manager (e.g. the form or component’s top-level container) would have to pass the instance on to every child that could hold it (probably because the children implemented an interface themselves). Components that had no interest in this interface would still be responsible for passing it on.

Messages, however, are already part of every UIComponent’s interface (because it implements IEventDispatcher): they allow listeners to hook into the messages; the message framework moves the event objects through the containership model; and the event objects themselves can change without changing the interface.

Message-Based MVC

The Ultimate Checkbox List Pattern resembles a Model-View-Controller: the item renderer would be the view; the list of selected items would be the model; and the event listeners on the list manager would be the controller. In an classc MVC pattern, the controller would push the changes into the view, and therefor would need to know how it worked (i.e. what method to call or property to push). The UCLP has the model pushing a change notification into a generic listener in the view, and then the view pulls the change information from the model; the module (and the controller, for that matter) do not know anything about the view besides a reference to the view’s notification listener.

Matching By Value vs. Matching By Reference

As shown in the sample application, one can use a more robust test to see if a Thingie is in the selected list than simply checking getIndexOf(). While the “thingie” might be a complex Value Object, this pattern also lends itself to simple data objects that might be dynamically created to wrap one or two column values. In this case, the object itself might not come from a global (i.e. singleton) store; one might have several simple instances that represent the same values, but not the same instances in memory.

For example, in the sample application (which has View Source)

 

Sample Message Based Checkbox List Application
click for SampleMessageBasedCheckboxListApplication

 

the AmISelected method checks if the data is selected, not just if the Thingie instance in the event is also on the list. Actually, the original version had a middle section that used api.business.gov to show a grid that was not even Thingie objects, but it has no crossdomain.xml, so…

Use this pattern to support your needs: if you have different representations of the same concept and you want to select or de-select the concept, then make the AmISelected check if the concept is on the list; if the objects in question are references to singleton objects on a central list (e.g. value objects), then check if the object itself is referenced by the list.

Let Me Know

Let me know what you think of this pattern. Let me know how I could explain it better. How have you improved it ?

Multiple States and Multiple Dependencies Using Message-Based Checkbox Patterns

Fourth in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

While a basic Ultimate Checkbox List Pattern uses only a single Boolean value – e.g. isSelected – its questioning event can allow more than just one answer: in addition to finding out if a row is selected (e.g. checking a checkbox), a questioning event can determine if a specific list item is visible or enabled at all. For example, the current user might not have rights to see a particular value; the page might have a terse or verbose option; some criteria might be selectable based on a separate criteria selection; or a set of items might have a maximum number of selections.

Like the selected state, the enabled state of a list item could be embedded in the item data itself, however one can choose to extend the Ultimate Checkbox List Pattern to. As each change in the list (or its proxy) makes every item check its state (see Multiple Views Using a Message-Based Checkbox Pattern), disabling any or all items is as easy as disabling one (remember that only visible items have item renderers with listeners which check state).

public class ThingieEvent extends Event
{
    public function ThingieEvent(...)
    {
        ...
    }
    public var thingie : Thingie;
    public var isSelected : Boolean = false;
    public var isEnableded : Boolean = true; // new flag public var notificationListener : Function;
}

The item renderer registers a listener the first time it checks the current item’s state by adding it to the questioning event:

...
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data as Thingie;
        theEvent.notificationListener = this.onExternalThingieChange;
        this.dispatchEvent(theEvent);
        isThingieSelectedCheck.selected = theEvent.isSelected;
        isThingieSelectedCheck.enabled = theEvent.isEnabled;
...

And whenever the item renderer’s notification listener indicates something external changed, it will check the state of the specific data currently in the item renderer.

    private function onExternalThingieChange(event : Event) : void
    {
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data as Thingie;
        this.dispatchEvent(theEvent);
        isThingieSelecctedCheck.selected = theEvent.isSelected;
        isThingieSelecctedCheck.enabled = theEvent.isEnabled;
    }

On the list manager side, the first time the item renderer asks for a selection status by dispatching a questioning event, the list manager adds the notification listener (if present) using weak references. It can add the callback as a listener directly to the data list (e.g. ArrayCollection), or it can add it to a separate IEventDispatcher object in order to proxy events explicitly from multiple sources (e.g. signal a change when the _thingieList changes and when the user changes between “terse” to “verbose”).

    private var _thingieList : ArrayCollection = new ArrayCollection();
    private var _thingieListProxy : EventDispatcher = new EventDispatcher();
      ...
        _thingieList.addEventListener(CollectionEvent.COLLECTION_CHANGE, onThingiesChange);
        context.addEventListener(Event.STATE_CHANGE, onThingiesChange); // something else that requires a change-check
      ...

    private function onThingiesChange(event : Event = null) : void
    {
        _thingieListProxy.dispatchEvent(new Event(Event.CHANGE));
    }

    private function onIsThingieSelected(event : ThingieEvent) : void
    {
        event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);
        event.isEnabled = (context.currentState == SELECTABLE_STATE) && (_thingieList.length < MAX_SELECTED_THINGIE_COUNT);
        if (event.notificationListener != null)
            _thingieListProxy.addEventListener(Event.CHANGE, notificationListener, false, 0, true);
    }

If the onThingsChange event carried information, it would link the listener and the dispatcher more tightly than we want. Using a generic Event with the type Event.CHANGE (the simplest possible notification) insures that the dispatcher can send that notification for any reason it wants; it is not restricted by any required or expected event parameters.

For those who like sequence diagrams:sequence diagram for multiple=

(Update: sample application in the final installment)

Multiple Views Using a Message-Based Checkbox Pattern

Third in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

The previous post showed how one can have an item renderer communicate with one of its containers to set and retrieve the selected (e.g. checked) state of the item renderer’s data. If, however, the same data (and its selected state) appear in more than one view, one needs to add another set of notifications to the pattern.

If something other than a particular item renderer changes the values in the thingieList, the item renderer needs to know to change the checkbox status. Rather than iterating through the children of the DataGrid or List to find all the ItemRenderers to tweak them, we can have sort of a “push” notification: the item renderer passes a listener function to the list manager the first time it asks for an item’s selected status, and external changes call that listener. To make things as generic as possible, the listener does not expect any specific type of event (i.e. the event does not contain information about the change); it simply checks its own status whenever it’s called.

This combination seems complicated, but it’s built on what we’ve done before:

  • The view dispatches an AmISelected event with a reference to its event listener function in it.
  • The list controller adds the event listener
  1. Something changes the list
  2. The list dispatches a CHANGE (or COLLECTION_CHANGE) event to all the listener functions
  3. The view listener functions dispatch an AmISelected event (without a listener reference in it)
  4. The list controller received the AmISelected event object and sets its .isSelected property based on the list
  5. The item renderer checks the .isSelected property and updates its display based on the answer


This causes a lot of events that don’t actually find any changes (i.e. every item renderer whose data have not be selected or deselected), however the cost for these events is low and the value of simplicity is high.

The item renderer registers a listener the first time it checks its data’s status:

 ...
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data.thingie;

        theEvent.notificationListener = this.onExternalThingieChange; this.dispatchEvent(theEvent); // ---- listeners execute here

        isThingieSelectedCheck.selected = theEvent.isSelected;
 ...

And the item renderer’s listener function checks the status

private function onExternalThingieChange(event : Event) : void
{
    var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
    theEvent.thingie = data.thingie;
    this.dispatchEvent(theEvent);
    isThingieSelectedCheck.selected = theEvent.isSelected;
}

On the list manager side, it adds the callback function (if present) as a listener using weak references. It could add the callback as a listener directly to the data list or to a separate IEventDispatcher object if it was going to fire events explicitly

private function onIsThingieSelected(event : ThingieEvent) : void
{
    event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);

    if (event.notificationListener != null)
        _thingieList.addEventListener(CollectionEvent.COLLECTION_CHANGE, event.notificationListener, false, 0, true);
}

By adding one notification, changes to the selection list automatically update all items whether they are visible or become visible later, so the user can can modify or clear the list without tight coupling with all the other views that add and remove items.

(Update: sample application in the final installment)

Go Ask Your Container

First in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

One of the things I had to learn moving from Windows programming to Flash/ActionScript programming was all the asynchronous patterns (aka two-part procedures). If one needs to load a resource in the middle of a process, one cannot just call a loader and wait for the results before continuing. One has to register an event listener to the loader object and put the remainder of the process into that listener function. When the loader is done loading, it calls the listener, and the rest of the process goes on its merry way. While this is indeed asynchronous programming, events themselves are not asynchronous.

Events are dispatched (aka “fired”, “launched”, “broadcast”, “thrown”) from classes implementing IEventDispatcher – usually by descending from or containing the class EventDispatcher – by calling the event handler functions (“listeners”) previously registered. The dispatcher does not care how many listeners have registered themselves or what they do: it just calls every one registered for a particular message.

Event handlers are, at their core, callback functions. One can call them explicitly, but they are designed to be registered with a dispatcher, and wait for it to call them. One should keep these callback functions very lightweight because events themselves are not asynchronous.

When one to fires an event by calling a dispatcher’s dispatchEvent method, the method literates through the list of registered listener functions, calling each one with the Event object as a parameter, and waiting for it to return before calling the next listener function. Then the dispatchEvent method itself returns. The code that calls dispatchEvent can assume that, when that call returns, all the listeners have had a chance to see and modify the Event object.

One can use events as a bidirectional messages between the dispatcher and the listeners, not just a one-way notification system; the event object can receive information from the listeners as well as send information. Combined with bubbling events that allow containers to get events without registering with the originating dispatcher, this patterns allows nested objects like ItemRenderers to ask questions of their high-level containers without each intermediate container passing the events up and the results down. This relationship is a loosely-linked one: the dispatcher does not know what object is setting the answer properties of the Event object; the listener does not know what object is dispatching the Event object. The form can add or remove containers without breaking.

The Event class already has one Boolean property that is designed for listeners to set: the defaultPrevented property. Listeners can call event.preventDefault() to set this, and the dispatching code can check the value (the dispatchEvent method itself returns this value as well).

For example, an ItemRenderer needs to know if the data it is displaying is part of the set that the user wants to focus on. The data itself does not know, but the top-level form object does. The ItemRenderer can dispatch an event containing its data object and a property for the current status.

public class AmIInUserFocusEvent extends Event
{ 
    public function AmIInUserFocusEvent(type : String = AM_I_IN_FOCUS, bubbles : Boolean = true, cancelable : Boolean = false) 
    { 
        super(type, bubbles, cancelable);
    }

    public var rowData : RowData; public var isInUserFocus : Boolean; 
}

In the ItemRenderer:

 ...
       var newEvent : AmIInUserFocusEvent = new AmIInUserFocusEvent(AM_I_IN_FOCUS, true);
       newEvent.rowData = this.data as RowData;

       this.dispatchEvent(newEvent); // ---- listeners execute here 

       if (newEvent.isInUserFocus) 
           text.styleName = "focusStyle"; 
       else 
           text.styleName = "neglectedStyle"; 
 ...

In some container that holds the item renderer’s list or grid :

 ... 
        this.addEventListener(AM_I_IN_FOCUS, onFocusQuestion);

        ....

    private function onFocusQuestion(event : AmIInUserFocusEvent) : void
    {
        event.isInUserFocus = focusList.contains(event.rowData); 
    }
 ...

To summarize, in additional to sending notifications and data out, events can also get answers. ActionScript’s built-in event framework allows loosely-coupled communication between different parts of a form, even across component bounds.

(Update: sample application in the final installment)

Put out the net, then jump

I came to ActionScript from Delphi: a Windows tool. In Windows, most things are synchronous, even database calls. We would amuse ourselves by building a database query component that used a thread to make it wait asynchronously for the result.

Learning ActionScript and Flex meant that I had to learn how to deal with lots of asynchronous processes. Lots of code gets broken into a before-the-call method and an after-the-call listener. I hate using global variables (see below) to pass data between these two pieces; I always prefer to use the event itself to pass data between the two (e.g. event.target).

Be that as it may, it’s easy to follow the pattern of coding for asynchronous events without really understanding them. I’ve seen a lot of sample code that starts an object’s operation before setting the listeners that will process the result.

var theLoader : Loader = new Loader();
theLoader.load(new URLRequest("http://www.site.com"));
theLoader.addEventlistener(Event.COMPLETE, onCompletion);

If you call .load() before you set the listener, the load might complete before you registered the listener. Now, the realities of ActionScript (e.g. single-threading) probably make it impossible that this will happen under normal circumstances, however good coding is important.

var theLoader : Loader = new Loader();
theLoader.addEventlistener(Event.COMPLETE, onCompletion);
theLoader.load(new URLRequest("http://www.site.com"));