Modular flex (4) applications 101

March 27, 2011

How to use modules in the same project:

  1. Define an interface for your module as the following. The whole point of modular app is to program to abstract interfaces so that different parts of your app have less dependency on one another; it also makes it easier to test:package
    {
    import flash.events.IEventDispatcher;
     

    public interface IInnerModuel1 extends IEventDispatcher
    {
    function foo():void
    }
    }

  2. Create a new module by right-click on the project on the Package Explorer> New > MXML Module.  Flex then generates a spark module (s:Module) for you. The module can has its own namespace; if it does, that means the resulting .swf file will be compiled into a subfolder that corresponds to its namespace structure, like  “/debug-bin/com/mh/test/flex/modules/MyInnerModule1.swf” or something.<s:Module xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    implements="IInnerModuel1">
     

    <fx:Script>
    <![CDATA[
    public function foo():void
    {
    myFooLabel.text = "Yo! What's up?";
    }
    ]]>
    </fx:Script>
    ...

    </s:Module>

  3. Add the module to the project by right-click  > Project Properties > Flex Modules > Add and navigate to the .mxml or the .as component.
  4. Load the module for the main app to use. You can do this using the following tag in your main app:
    <s:ModuleLoader id="innerModule1Loader" url="com/mh/test/flex/modules/MyInnerModule1.swf" />
  5. In order to access your module from main WindowedApplication, you can do this:protected function button1_clickHandler(event:MouseEvent):void
    {
     

    if(innerModule1Loader.child == null)
    return;

    var iChild:* = innerModule1Loader.child as IInnerModuel1;
    iChild.foo();

    }

Some links:
How to pass data to modules and access modules from main app and vice versa (Flex 4)

How to use modules from different Flex projects

Step by step of how to use modules in Flex 3

 

Passing on complex object when declaring an ActionScript/MXML component

March 26, 2011

If you want to configure a complex object and pass it on to an ActionScript component when declaring the component, you can use the default property for the latter to pass in the former. Here:

//actionscript
package com.adobe.login.control
{
...
[DefaultProperty("handlers")]
public class SimpleController extends UIComponent
{
[ArrayElementType("com.adobe.login.control.handler.Handler")]
public var handlers : Array;

public function SimpleController()
{
addEventListener( FlexEvent.INITIALIZE, handleInitialize );
}

private function handleInitialize( event : FlexEvent ) : void
{
for( var i : int = 0 ; i < handlers.length ; i++ )
{
var handler : Handler = Handler( handlers[i] );
parent.addEventListener( handler.eventId, handler.execute );
}
}
}
...
}

// mxml
<mx:Application ...
...
<mx:Script>
<![CDATA[
...
[Bindable]
private var pm : MainPM = new MainPM();

]]>
</mx:Script>

<control:SimpleController>
<handler:LoginHandler
client="{ pm }"/>
</control:SimpleController>
...

* vs. Object in ActionScript 3

March 22, 2011

ActionScript 3 doesn’t support Generics like some other languages such as Java. In the case you need to return a Generic type, e.g., your client code is expecting certain type, but the code that provides the service doesn’t know what type it is going to be, you simply use star (*), as opposed to Object:


public function createWindowInstance(type:Class,
allowMultipleInstances:Boolean = false):*
{
...
var windowToOpen:*;
windowToOpen = new ClassFactory(type).newInstance();
spark.components.Window(windowToOpen).open();
return windowToOpen;
}

Passing on objects through constructor

March 20, 2011

I am reading this nice article about architecting your application using Model View Presenter. In the application where you have lots of parts that work together and share some of the plumbings, the way you pass those plumbings around is that you have some centralized objects that are responsible for instantiating both the shared objects and those parts and you pass on the former to the latter  through their constructors:

// A part that asks for the infrastructure such as RPC service, event bus, etc..

public ContactsPresenter(ContactsServiceAsync rpcService,
HandlerManager eventBus, ContactsView<ContactDetails> view,
List<ColumnDefinition<ContactDetails>> columnDefinitions)

...

// The application controller, which constructs most of the parts that do the work.

public AppController(ContactsServiceAsync rpcService,
HandlerManager eventBus) {
this.eventBus = eventBus;
this.rpcService = rpcService;
bind();
}
...

// GWT's bootstrap process calls this "Main" that sets things in motion

public class Contacts implements EntryPoint {
public void onModuleLoad() {
ContactsServiceAsync rpcService = GWT.create(ContactsService.class);
HandlerManager eventBus = new HandlerManager(null);
AppController appViewer = new AppController(rpcService, eventBus);
appViewer.go(RootPanel.get());
}
}

The point is that a working bee (such as the ContactsPresenter) only needs to know the minimal (what he needs to know in order to get his work done). If he needs an rpcService, he does so by simply asking for a rpcService object in their constructors, or maybe have a setter property that can be used by a controller to assign a rpcService to it; but they should not set the rpcService object by themselves, like this:

// an anti-pattern ContactsPresenter object:
this.rpcService = ModelLocator.instance.rpcService;

Think about the scenario when the rpcService object later is to be moved to somewhere else; then we would have to change the code in all the working bees that use this rpcService. If we set the rpcService object through some centralized place (such as in module loader and appController), we would only need to change those few places. Another bad thing about doing so it that then your working bees start to know about too many details (like they know that the rpcService stores in the model locator singleton, which might change later on.) and start to dependent on those assumptions/details.  These couplings make change harder.

A better approach would be to inject those information from outside, such as managed by a few centralized objects, as we did from the beginning.

I think the real world analogy is that a working bee is expected to simply get the work done and not beyond. If he needs something, he would ask his manager, “I need a truck”. It’s the manager’s job to assign him a truck instead of him going out and looking for a truck by himself. (Or maybe not.)

P.S., Later I found out that a more trendy way of saying “to pass on objects” is “to inject the objects”. So the title of this post can then be rephrased as “constructor injection”.

Access main window application (top-level application) in Flex 4/AIR 1.5

March 6, 2011

Sometimes you need to access the top-level/main application (in terms of AIR desktop, it would be the main window, a.k.a the s:WindowedApplication instance that you set as “Default Application” under the default package) directly from your object. The reason for this could be that you have some sort of window manager that you roll out by your own that resides in the “default application” which manages all the windows in your application. You can communicate with the window manager via some event mechanism, or simply directly send a message to it from within your window object, like this:

FlexGlobals.topLevelApplication.windowManager.closeWindow(this);

FlexGlobals and topLevelApplication work on Flex 4, AIR 1.5 and Flash Player 10.

How to rename a project in Visual Studio 2010

February 26, 2011
  • You can rename any project by right-clicking the project in Solution Explorer and select Rename. But this doesn’t change the physical folder name. To change the physical folder name, first right-select “Open Folder in Window Explorer”, then close the solution (File> Close Solution), then rename the folder that contains the project (the folder in which the *.csproj file resides).
  • The assembly name and the namespace of the projects under this solution still remain unchanged (suppose you’ve changed namespaces and/or assembly names for some of them), to fix this, while the solution is still closed, open their individual .csproj file with a text editor and modify the <RootNamespace> and <AssemblyName> nodes to reflect the changes.
  • Last but not least,  When you reopen the solution, VS won’t be able to load the project. To fix this, remove the stale project entry in Solution Explorer, then right-select the Properties of the solution > Add > Existing Project and navigate to select the *.csproj file.

Automatically size the app Window to accommodate the content

January 24, 2011

SizeToContent=”Height/Width/WidthAndHeight”

Use .sqliterc in Windows

January 22, 2011

Here.

1. In DOS command, type “set” and find where it says “HOMEDRIVE” and “HOMEPATH”;

2. Navigate to the home dir and type “edit .sqliterc” to create the resource file, something like:

.mode column
.header on
.nullvalue NULL

Flex compiler: Keep generated ActionScript

November 12, 2010

Project properties -> Flex Compiler -> Additional compiler arguments ->

Add “-compiler.keep-generated-actionscript” (without quotes)

Here:

List of Flex Compiler ArgumentsUnderstanding Flex Compilers

Data binding 101 (flex gumbo)

September 19, 2010
  • Data binding is the plumbing (or “out-of-the-box” feature) provided by modern presentation frameworks such as Flex SDK and WPF. The general idea is to facilitate communications concerning value changes among different objects, so that the application developers can focus on higher level tasks. Most of these plumbings are optimized for declarative code (MXML, XAML and metadata tags in your procedural code). For example, if you use [Bindable],<fx:Binding> meta tags or curly braces (MXML data binding expressions), Flex compiler will give compilation warnings about whether it thinks the data bindings you set up will work nor not; while you don’t get this kind of nice friendly reminder if you use mx.binding.utils.BindingUtils or mx.binding.utils.BindingUtils.ChangeWatcher directly.
  • Data binding is nothing magical than using event listeners to watch for changes on objects/values and then get the updated values. There are two sides of the equation:A. You tell the compiler which object/value you’d like to watch, like so:[Bindable(event="selectedEmployeeChanged")]
    public function get selectedEmployee():Employee
    {
    return _selectedEmployee = v;
    }

    Here you tell the Flex to get the value for _selectedEmployee whenever the interested parties are notified by the event “selectedEmployeeChanged”.  If you don’t specify an event name, flex will automatically associate this data bound value with an event named “propertyChange” and will dispatch that event for you behind the scene. This is convenient for the developer as you don’t need to care about when to fire the event(s) and which event(s) you need to listen for the involved parties, etc..

    B. You tell the compiler when the object/value is changed, like so:
    public function set selectedEmployee(v:Employee)
    {
    if(!v.equals(_selectedEmployee))
    {
    _selectedEmployee = v;
    dispatchEvent(new Event("selectedEmployeeChanged", true, true));
    }
    }

    Here you trigger the data binding (chain) by firing the “selectedEmployeeChanged” event which you defined in step A. Flex then will copy the values for you to the interested parties (destinations of the data binding.)

  • To really understand data binding, it’s important to understand under what conditions the compiler will do the work for you (or the opposite, “when data binding is not supported”) when you set up your data binding (using <fx:Binding>, [Bindable] and data binding expressions). It helps to give examples to show when it doesn’t work. Scenario: You want to watch property changes in another class. For example, if I have an object called FacebookStatus and it contains properties such as numberOfLikes and numberOfDislikes (a feature pending further proof by the product manager) and I have another object called UserInfo which contains a FacebookStatus object. If my FacebookStatus object wants to watch changes of numberOfLikes of FacebookStatus, I can’t simply say:
    <!--In FacebookStatus-->
    public function set numberOfLikes(v:int)
    {
    _numberOfLikes = v;
    dispatchEvent(new Event("statusChange"));
    }

    <!--In UserInfo-->
    [Binding(type="statusChange", type="flash.events.Event")]
    public function handleUserStatusChange(event:Event):void
    {
    //do something to react...
    }

    In the example above, UserInfo will never gets notified by “statusChange” as the compiler won’t look into another object to make the [Binding] tag work. In this case, you can do the binding work yourself by using mx.binding.utils.BindingUtils.bindSetter().
  • It helps to understand what the data binding doesn’t do as well as the trade-offs of having the compiler doing the data binding for you. Sometimes it’s better to do the work yourself. For example, if you have a Watch object that works somehow like a timer (stores information about the minutes elapsed since certain point of time) and you want to show it on the screen, you have to call a function to constantly get the minutes value (e.g., in a loop) in order to get the UI updated constantly. Merely setting up the data binding from the Watch object to the UI is not sufficient.Also, since the compiler needs to create a lot of listeners under the hook, it can consume much more memory and involves deep function stack calls to eventually get the values copied around.
  • If you set up your data binding in <fx:Binding> tags or using [Bindable] metadata tags, Flex sets up the data binding at the “initialization” stage of the UIComponent’s life cycle. It uses try/catch to hide the null objects/values errors and update the values when available.
  • If you have a data object with complex properties, which has complex properties, etc., (e.g, employee.supervisor.department.id) and you want to data bind it’s property, then each node in the data binding chain needs to be set up as data bindable. This won’t automatically happen; but the compiler will give a friendly warning about it if it finds any of the properties in the chain is not data bound.
  • You can watch for more than one event on a value change:[Bindable("change")]
    [Bindable("valueCommit")]
    public function get selectedIndices():Vector.<int>
    {
    return _selectedIndices;
    }

Here are several interested read (last one in Chinese):
Two-Way Data Binding in Flex 4
Michael Labriola’s presentation entitled Diving in the Data Binding Waters
Flex 数据绑定易犯的错误:普遍的误用和错误