2010-11-27 16 views
5

Voici un exemple de composant personnalisé. Il est juste une boîte avec une étiquette de titre et une image proche (X):Comment placer des nœuds enfants MXML dans un composant Flex 4 personnalisé?

<?xml version="1.0"?> 
<mx:Canvas ... > 
    <s:VGroup> 
     <s:Label text="(HEADING TEXT)" ... /> 

     (INSTANCE MXML) 

    </s:VGroup> 
    <mx:Image ... /> 
</mx:Canvas> 

Lorsque vous utilisez le composant dans un document MXML, je voudrais avoir le « (TEXTE heading) » remplacé par un paramètre (devrait être facile) ainsi que le "(INSTANCE MXML)" avec plusieurs étiquettes, entrées de texte, cases à cocher, etc. (peut-être plus difficile).

J'ai trouvé this script-based method, mais je voudrais un nettoyant compile-temps solution, s'il en existe une. Aucune suggestion?

Répondre

10

MyComponent.mxml:

<?xml version="1.0"?> 
<mx:Canvas ... > 
    <fx:Script> 
     [Bindable] 
     public var headingText:String = "Default Heading Text"; 

    </fx:Script> 
    <s:VGroup> 
     <s:Label text="{headingText}" ... /> 

     (INSTANCE MXML) 

    </s:VGroup> 
    <mx:Image ... /> 
</mx:Canvas> 

qui vous permettra de passer dans le HeadingText comme ceci:

<my:MyComponent headingText="Custom Heading Text" /> 

Vous pouvez suivre la même approche pour d'autres valeurs simples que vous voulez passer; déclarez simplement une propriété publique, rendez-la liable, puis, dans votre composant, utilisez la liaison de données pour connecter la propriété à sa destination (ou à ses destinations).

Vous pouvez faire la même chose pour les propriétés complexes (comme votre INSTANCE MXML). Il ressemble à ceci, lorsque vous l'utilisez:

<my:MyComponent> 
    <my:thePropertyName> 
    <s:Label text="whatever..." ... /> 
    <(OTHER MXML CONTENT) /> 
    </my:thePropertyName> 
    <my:someOtherPropertyName> 
    .... 
    </my:someOtherPropertyName> 
</my:MyComponent> 

Pour un exemple de la façon de mettre en œuvre, vous pouvez consulter la propriété mxmlContent du composant spark.components.Group dans le cadre flexible. La source est trop longue à poster ici, et je n'arrive pas à trouver un lien en ligne directement à la source; mais l'idée de base est la suivante (vous pouvez faire tout ce qui suit dans un bloc <fx:Script> dans un fichier MXML - vous ne devez pas faire un pur comme classe pour le faire):

[1] déclarer la propriété comme type Array, avec les métadonnées ArrayElementType pour indiquer le type que vous souhaitez que le tableau contienne.

[ArrayElementType("mx.core.IVisualElement")] 
public function set mxmlContent(value:Array):void { 
    _mxmlContent = value; 
} 
private var _mxmlContent:Array; 

[2] Vous aurez besoin d'un peu de logique en boucle sur le réseau lors de l'exécution, et ajoutez le contenu du tableau à la liste d'affichage du composant. Le remplacement createChildren est un bon endroit pour déclencher cela. Ce qui suit est dérivé librement de la mise en œuvre de setMXMLContent() méthode de l'étincelle Group. Elle ne couvre pas tous les cas possibles, mais ça va vous aider à démarrer:

override protected function createChildren():void { 
    super.createChildren(); 
    if(_mxmlContent == null) return; 
    for (i = 0; i < _mxmlContent.length; i++) { 
     var elt:IVisualElement = _mxmlContent[i]; 
     addElement(elt); 
    } 
} 

Alors maintenant, votre composant aurait une propriété appelée mxmlContent, que vous pouvez définir à partir d'un composant MXML parent en utilisant la syntaxe:

<my:MyComponent> 
    <my:mxmlContent> 
     ... (MXML ELEMENTS HERE) ... 
    </my:mxmlContent> 
</my:MyComponent> 

Vous pouvez créer votre nouvelle propriété dans le default property de votre composant en appliquant les métadonnées: [DefaultProperty("mxmlContent")] votre classe de composants. Pour faire cela à partir de mxml, enveloppez simplement la définition de métadonnées dans un élément <fx:Metadata>. see here for example of fx:Metadata.


mettre tout ce qui précède ensemble, et vous obtiendrez quelque chose que vous pouvez utiliser comme ceci:

<my:MyComponent headingText="Custom Text Here"> 
    (CUSTOM MXML CONTENT HERE) 
</my:MyComponent> 

Edit: je devrais faire quelques notes ici:

  1. Les composants "Halo" (tels que mx:Canvas) ne prennent pas en charge addElement() comme utilisé ci-dessus, donc vous voudrez probablement utiliser addChild() à la place.

  2. Vous devriez (probablement) utiliser des composants d'étincelles au lieu de composants halo. Signification, utilisez <s:Group> comme base au lieu de <mx:Canvas>. Si vous faites cela, alors votre composant héritera de la propriété mxmlContent décrite ci-dessus. Si vous voulez que votre composant ait sa propre propriété "content" (ou même plusieurs propriétés de contenu), nommez-les simplement différemment.

+0

Eh bien, ce n'est pas exactement une solution de * compilation au moment *, mais peut-être que le traitement de l'exécution ne peut pas être évité. Vous méritez certainement beaucoup de remerciements et puisque personne d'autre ne s'est rapproché, j'accepterai cette réponse. – W3Coder

+0

@ W3Coder: merci d'accepter. Je sais que vous vouliez une solution de compilation, mais - peu de temps pour créer votre propre générateur de code - il n'y a pas moyen d'y arriver. Pour ce que ça vaut cependant: c'est la même approche que celle utilisée par le framework Flex pour gérer le contenu enfant, donc vos composants, écrits de cette manière, devraient être aussi efficaces que n'importe quelle solution de compilation. bonne chance! revenez et faites-nous savoir si vous trouvez des solutions différentes/meilleures. – Lee

7

C'est génial. Merci pour cette info.

Comme je n'avais pas besoin d'un tel contrôle, j'ai un peu simplifié cette solution.

Code pour notre conteneur MyComponent.mxml:

<s:Group ... > 
<fx:Script> 
    <![CDATA[ 

    [Bindable] 
    [ArrayElementType("mx.core.IVisualElement")] 
    public var content:Array; 

    ]]> 
</fx:Script> 

<s:Group width="100%" height="100%" mxmlContent="{content}" /> 

et utilisation:

<myComponents:MyComponent 
    xmlns:myComponents="myComponents.*" 
> 

    <myComponents:content> 
     <s:Label /> 
     <s:Label /> 
     <AnythingWeWant... 
    </myComponents:content> 

</myComponents:MyComponent> 

Hope this helps personne. À la vôtre.

+1

Super article. Juste ce dont j'avais besoin! Kamil, merci de poster votre code ... c'est très simple comme ça. – Ofir

+2

Si vous ajoutez ' [DefaultProperty (" content ")]' à MyComponent.mxml, vous pouvez supprimer les balises '' lorsque vous utilisez la classe. Voir au dessus. – Stephenr