Flex Modules – Utiliser des interfaces ActionScript pour communiquer avec l'application
Les derniers articles sur les modules Flex montraient comment créer une communication module-application et vice-versa. Cependant, ces techniques basées sur les propriétés child de Module Loader ou parentApplication créent une forte dépendance entre vos classes, ce qui empêche la ré-utilisabilité de vos modules.
La solution pour créer des modules peu couplés avec l'application est d'utiliser des interfaces ActionScript. Les modules vont implémenter une interface et votre application va appeler les méthodes ou fixer les propriétés définies dans l'interface. L'interface va ainsi définir les points d'accès vers votre module. Le module implémente une interface connue de l'application ou l'application implémente une interface connue par le module. Cela vous permet d'éviter les dépendances fortes entre module et application.
Dans l'application mère, quand vous souhaitez appeler les méthodes d'un module, vous devrez faire un cast (conversion de type) de la propriété "child" du ModuleLoader" en une instance de votre interface.
L'application suivante vous permet de personnaliser l'apparence du module chargé en appelant les méthodes définies par l'interface IModuleInterface. L'application appele aussi la méthode getModuleName(). Cette méthode renvoie une valeur du module et fixe un variable locale.
L'application principale
<?xml version="1.0"?>
<!-- modules/interfaceexample/Main.mxml -->
<mx:Application xmlns="*"
xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.events.ModuleEvent;
import mx.modules.ModuleManager;
[Bindable]
public var selectedItem:Object;
[Bindable]
public var currentModuleName:String;
private function applyModuleSettings(e:Event):void {
// Cast the ModuleLoader's child to the interface.
// This child is an instance of the module.
// You can now call methods on that instance.
var ichild:* = mod.child as IModuleInterface;
if (mod.child != null) {
// Call setters in the module to adjust its
// appearance when it loads.
ichild.setAdjusterID(myId.text);
ichild.setBackgroundColor(myColor.selectedColor);
} else {
trace("Uh oh. The mod.child property is null");
}
// Set the value of a local variable by calling a method
// on the interface.
currentModuleName = ichild.getModuleName();
}
private function reloadModule():void {
mod.unloadModule();
mod.loadModule();
}
]]>
</mx:Script>
<mx:Form>
<mx:FormItem label="Current Module:">
<mx:Label id="l1"
text="{currentModuleName}"/>
</mx:FormItem>
<mx:FormItem label="Adjuster ID:">
<mx:TextInput id="myId"
text="Enter your ID"/>
</mx:FormItem>
<mx:FormItem label="Background Color:">
<mx:ColorPicker id="myColor"
selectedColor="0xFFFFFF"
change="reloadModule()"/>
</mx:FormItem>
</mx:Form>
<mx:Label text="Long Shot Insurance"
fontSize="24"/>
<mx:ComboBox labelField="label"
close="selectedItem=ComboBox(event.target).selectedItem">
<mx:dataProvider>
<mx:Object label="Select Module"/>
<mx:Object label="Auto Insurance"
module="AutoInsurance.swf"/>
</mx:dataProvider>
</mx:ComboBox>
<mx:Panel width="100%"
height="100%">
<mx:ModuleLoader id="mod"
width="100%"
url="{selectedItem.module}"
ready="applyModuleSettings(event)"/>
</mx:Panel>
<mx:Button id="b1"
label="Reload Module"
click="reloadModule()"/>
</mx:Application>
L'interface implémentée par le module
package {
import flash.events.IEventDispatcher;
public interface IModuleInterface extends IEventDispatcher {
function getModuleName():String;
function setAdjusterID(s:String):void;
function setBackgroundColor(n:Number):void;
}
}
Le module
L'exemple suivant définit le module chargé dans l'exemple précédent et implémente l'interface IModuleInterface.
<?xml version="1.0"?>
<!-- modules/interfaceexample/AutoInsurance.mxml -->
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%"
height="100%"
implements="IModuleInterface">
<mx:Panel id="p1"
title="Auto Insurance"
width="100%"
height="100%"
backgroundColor="{bgcolor}">
<mx:Label id="myLabel"
text="ID: {adjuster}"/>
</mx:Panel>
<mx:Script>
<![CDATA[
[Bindable]
private var adjuster:String;
[Bindable]
private var bgcolor:Number;
public function setAdjusterID(s:String):void {
adjuster = s;
}
public function setBackgroundColor(n:Number):void {
// Use a bindable property to set values of controls
// in the module. This ensures that the property will be set
// even if Flex applies the property after the module is
// loaded but before it is rendered by the player.
bgcolor = n;
// Don't do this. The backgroundColor style might not be set
// by the time the ModuleLoader triggers the READY
// event:
// p1.setStyle("backgroundColor", n);
}
public function getModuleName():String {
return "Auto Insurance";
}
]]>
</mx:Script>
</mx:Module>
L'application en ligne
Flex Source Code Download: Télécharger le code source complet de l'application
De manière générale, si vous voulez fixer des propriétés dans un composant dans un module en utilisant des valeurs externes, vous devriez créer des variables Bindable. Vous pouvez ensuite fixer les valeurs de ces variables dans la méthode définie dans l'interface. Si vous essayez de fixer des propriétés sur un composant directement en utilisant des valeurs externes, le composants pourrait ne pas être instancié au moment où le module est chargé et vous pourriez avoir une RTE (RunTime Error).
Articles similaires
- Flex Modules – Communication Application vers Module
- Flex Modules – Communication Module vers Module
- Flex Modules – Communication entre Module et Application
- Flex Modules – Pré-chargement de modules (preloading)
- Flex Modules – Les évènements de ModuleLoader (ready, loading, …)
Aucun trackbacks pour l'instant






5 novembre 2009
Merci pour cette excellente explication! Ce site est réellement très utile. Il m'a permis de gagner beaucoup de temps à de nombreuses reprises. Merci encore!
5 novembre 2009
Salut,
Dans l'exemple présent, le module MXML implémente une (seule) interface (en l'occurrence "IModuleInterface").
Savez-vous s'il est possible de déclarer plusieurs interfaces?
Note: Je cherche à exprimer, en MXML, l'équivalent du message suivant (ActionScript)
La casse "TimeChooser" implémente deux interfaces (IGhostInterface et ISelectorInterface).
J'ai effectué des recherches mais sans succès.
Merci,
Denis
5 novembre 2009
Salut,
il faut passer par la propriété "implements" du tag MXML. Pour de multiples interfaces, elles doivent être séparées par des virgules.
Par exemple:
Fabien
5 novembre 2009
Salut,
Je te remercie pour l'information. J'avais essayé, mais j'avais certainement fait une erreur de syntaxe.
En tous les cas, ça fonctionne.
Merci,
Denis
23 août 2010
Merci pour cette illustration c'est très utile, j'ai réussi à faire la connexion entre l'application racine et un module comme il est décrit sur le tuto par contre malheureusement j'ai pas réussi à l'établir entre 2 module , pour information le chargement d'un module dans un autre est faisable mais lorsque je teste l'objet "ichild" il retourne null ... une indice stp
Merci.
23 août 2010
Salut,
tu fais le chargement d'un module depuis un autre module? Tu passes bien dans l'évenement READY de ce module pour être sûr que son chargement est terminé?
Ah oui et sinon, assure toi qu'il implémente bien IModuleInterface si tu utilises le code de cet exemple, sinon le cast avec "as" va renvoyer null.
Si malgré tout, cela ne fonctionne pas, passe un coup en debug pour voir ou tu perds ton module
Fabien
24 août 2010
Merci pour votre réponse fabien, mais bon jusqu'à maintenant je sais pas d'où vient le problème, J'ai trouvé un nouveau moyen pour faire communiquer mes deux modules c'est à travers parentApplication.chargeurModule.child.findByKeys(...) le module fait appel à l'application principale ,puis l'id du chargeur ensuite child et finalement la méthode voulue.
Merci Sami.
24 août 2010
Effectivement. La méthode suivante est tout de même à préferer (plus clean):
http://www.flex-tutorial.fr/2009/10/15/flex-modules-communication-module-vers-module/
Fabien