Overriding default Flex/AIR mx.managers implementations

11 months ago malczak actionscript air flex comments Bookmark and Share

The problem is - You want to customize behavior of managers available in Flex/AIR framework. For example, You would like to change the way PopUpManager manager handles popup windows.

Most common solution to this problem is creating custom manager class and using this in code instead of default manager class. For example lets take a look at PopUpManager. If You want to customize addPopup method, You create Your own manager, lets call it PopManager, and later on You use it instead of standard PopUpManager class. Main advantage of using method described here is, that You can extend manager , and still use standard class to call all methods. This allows You to change the way the manager works without refactoring all Your code.

In further discussion I use PopUpManager as an example. PopUpManager is class with all public methods defined as statics. Internally to handle popup windows it uses instance of a PopUpManagerImpl class, IPopUpManager interface implementation. Implementation class is stored in singleton registry (mx.core.Singleton). All implementation classes for managers are registered at application startup by an instance of SystemManager class. To create singleton registry of classes mx.core.Singleton static method registerClass is used. Only one implementation per manager can be registered. The registration policy used is "first class in wins", all further calls are ignored. To use custom implementation You need to register it before SystemManager registers framework default ones. Default implementations are registered in SystemManager.mx_internal::docFrameHandler method. It is called before the instance of main application class in created.

The best (and seems to be the only possible) way to override framework implementations, is to implement IPreloaderDisplay in Your application and use it to register custom classes. IPreloaderDisplay interface implementor DownloadProgressBar is used as a visual preloader for a Flex/AIR applications. It can be set with use of Application.preloader property. Preloader is created and initialized by SystemManager (simplified description), before it registers default implementations for framework managers. To override any of implementations use initialize method of IPreloaderDisplay interface (other methods can be used as well).

package my.domain {
    public class MyPreloader extends DownloadProgressBar 
    {
        override public function initialize():void
        {
            super.initalize();
            Singleton.registerClass(
                            "mx.core.IPopUpManager", 
                            Class( my.domain.managers.MyPopUpManager ) );
        };
    }
}

From now on, custom IPopUpManager implementation will be used when static method of the PopUpManager is called. And an example code for custom IPopUpManager implementation

package my.domain.managers {
    public function MyPopUpManager extends PopUpManagerImpl 
    {
        private var instance : IPopUpManager;

        static public function getInstance():IPopUpManager
        {
            if ( !instance ) instance = new MyPopUpManager();
            return instance;
        };
    
        override public function addPopUp( ... ):void
        {
            super.addPopUp(...);
            /* custom code */
        }
    
    };
}

One static method always needs to implemented in Your class - getInstance. This method is used by Singleton class to add an instance of Your class to the registry.

In the same way You can overload managers listed below, as it can be seen not all framework managers can be changed.
BrowserManager
CursorManager
HistoryManager
LayoutManager
ToolTipManager
DragManager

Working example (right click to see source code):

Flash player (ver. 10.0.0) is required to see this content. Please update to newest possible version.

Get newest Adobe Flash player

entry was also published as a flex cookbook entry

Share |

Comments

10 months ago David Lance #0

Thanks for this entry. It was a huge help.

One thing I'd like to mention... Your code in the blog does not match the source code in the preloader's initialize() function. To all readers, follow the code example rather than the blog text. This is the correct preloader code...


Singleton.registerClass("mx.managers::IPopUpManager",
Class( com.segfaultlabs.cookexample.CookPopUpManager ) );
[/code]

Further, my requirement was to center the popup over the entire application rather than the parent container. Here's how I modified your code to make this work and it seems to work really well. I took the liberty of centering the popup on createPopUp since that's what we're always going to want to do, but you could just as easily remove that and make the extra call to centerPopUp.

[code]
override public function createPopUp(parent:DisplayObject, className:Class, modal:Boolean=false, childList:String=null):IFlexDisplayObject
{
var popUp:IFlexDisplayObject = super.createPopUp( parent, className, modal, childList );
centerPopUp(popUp);

return popUp;
}


override public function centerPopUp(popUp:IFlexDisplayObject):void
{
var sm:SystemManager = Application.application.systemManager;
popUp.move((sm.stage.stageWidth / 2) - (popUp.width / 2), (sm.stage.stageHeight / 2) - (popUp.height / 2));
}


Thanks again for the blog entry. Saved me tons of time.

10 months ago malczak #1

hi there David, thanks for Your comment and additional informations (code).
answering to your comment - code from blog entry uses different package naming than the one from example, but its is still correct ;)

10 months ago Kevin #2

It is possible to override ALL of the built in managers except for SystemManager. For ResourceManager, EmbeddedFontRegistry, and StyleManager, you have to do things a bit differently than with the list you provided above. These managers are registered by SystemManager before the initialize method of preloader is called (see SystemManager line 1880 in Flex 3.3) , so the trick is to register your custom implementation inside of a static initializer in your custom Preloader. Static initializers are called as soon as a class is referenced, and the preloader class is reference earlier in the SystemManager.initialize method.

So, your preloader would look something like

package mypackage {
public class MyPreloaded extends DownloadProgressBar {
staticInitializer();

private static function staticInitializer():void {
Singleton.registerClass("mx.resources::IResourceManager", MyCustomResourceManager);
Singleton.registerClass("mx.core::IEmbeddedFontRegistry", MyCustomEmbeddedFontRegistry);
Singleton.registerClass("mx.styles::IStyleManager", MyCustomStyleManager);
Singleton.registerClass("mx.styles::IStyleManager2", MyCustomStyleManager);
}
}
}




10 months ago malczak #3

@Kevin great idea !!!! Thanks a lot for sharing :) I will add this info to flex cookbook entry !

New comment

  1. (never shown, just for us for possible contact)

  2. (with http or https prefix)

  3. (use [code][/code] tags to post a code snippet)

  4. (javascript is required)

Website content premeditately commited by segfaultlabs (malczak & sobstel).
Layout by mlando. Icons by DryIcons.com. All rights reserved, of course.