I am attempting to prototype a modular application architecture utilizing the Apache Flex SDK 4.12.1 using Flex Modules. I have the following project structure.
CommonLib flex library. This project contains a single file, IPlugin.as as shown below.
{ import mx.core.IVisualElement; public interface IPlugIn { function get MyPlugin():IVisualElement; } }
ModuleProject flex application. This project contains two files. PluginModule.mxml which is the module I want to load and DemoForm.mxml which is the component I want to add to the main application.
// PluginModule.mxml <?xml version="1.0" encoding="utf-8"?> <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" xmlns:local="*" implements="Interfaces.IPlugIn"> <fx:Script> <![CDATA[ import mx.core.IVisualElement; private var _myPlugin:DemoForm = new DemoForm(); protected function button1_clickHandler(event:MouseEvent):void { container.addElement(new DemoForm()); } public function get MyPlugin():IVisualElement { if (_myPlugin == null) _myPlugin = new DemoForm(); return _myPlugin; } ]]> </fx:Script> <s:HGroup> <s:Button id="btn" label="Add DemoForm" click="button1_clickHandler(event)"/> <s:VGroup id="container"/> </s:HGroup> </s:Module> // Demoform.mxml <?xml version="1.0" encoding="utf-8"?> <s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" width="400"> <s:layout> <s:TileLayout/> </s:layout> <s:Button label="Button 1"/> <s:TextInput/> </s:Group>
FlexProject flex application project. This contains a single file with the intention of loading the PluginModule and DemoForm.mxml into it's BorderContainer.
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"> <fx:Script> <![CDATA[ import mx.core.IVisualElement; import mx.events.ModuleEvent; import mx.modules.IModuleInfo; import mx.modules.ModuleManager; import Interfaces.IPlugIn; private var moduleInfo:IModuleInfo; protected function button1_clickHandler(event:MouseEvent):void { moduleInfo = ModuleManager.getModule("PluginModule.swf"); moduleInfo.addEventListener(ModuleEvent.READY, renderModule); moduleInfo.load(null, null, null, this.moduleFactory); } private function renderModule(event:ModuleEvent):void { var module:Object = moduleInfo.factory.create(); var plugin:IPlugIn = module as IPlugIn; container.addElement(plugin as IVisualElement); // <-- Works! container.addElement(plugin.MyPlugin); // <-- Error: Skin cannot be found } ]]> </fx:Script> <mx:VBox> <s:Button click="button1_clickHandler(event)" label="Add Plugin"/> <s:BorderContainer id="container"> <s:layout> <s:VerticalLayout gap="10"/> </s:layout> </s:BorderContainer> </mx:VBox> </s:Application>
I can add the module directly to the application's container and everything seems to work. The application container will then display the 1 button implemented by PluginModule.mxml. However, when I try to add the Demoform to the application's container via the plugin.MyPlugin method I receive the following error.
Error: Skin for FlexProject.ApplicationSkin2.containerGrp.contentGroup.VBox5.container.BorderContainerSkin10.Group11.DemoForm13.RadioButton16 cannot be found.
I have tried this with numerous different controls including TextArea, TextInput, and RadioButtons. These all fail with similar errors. It appears that the main application cannot find the skins for these components!
Interestingly, if I instead allow PluginModule.mxml to add the DemoForm.mxml to it's own container it works fine. Though, this is not the behavior that I desire.
Any suggestions as to what might be occurring and how I can address it?