DevlogsDevlogs
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.
entry was also published as a flex cookbook entry
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 ;)
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);
}
}
}
@Kevin great idea !!!! Thanks a lot for sharing :) I will add this info to flex cookbook entry !
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...
Thanks again for the blog entry. Saved me tons of time.