Flex: À l'écoute CollectionEvent en composant personnalisé
-
29-09-2019 - |
Question
(EDIT: Je l'ai modifié ma question pour le rendre plus simple, désolé si certaines réponses sont hors contexte)
J'ai préparé un test réduit pour ma question:
Je suis en train de créer un composant personnalisé qui est étant alimenté avec des données XML provenant du serveur. Mon problème est que l'auditeur CollectionEvent ne soit pas tiré et étiquettes donc pas mis à jour -
Games.mxml (mon composant personnalisé avec l'auditeur):
<mx:Script>
<![CDATA[
import mx.events.*;
private var _xlist:XMLList;
[Bindable]
public function get xlist():XMLList {
return _xlist;
}
public function set xlist(x:XMLList):void {
_xlist = x;
trace("set(" + x +")");
list.dataProvider = x;
list.dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE, xlistChanged);
}
private function gameLabel(item:Object):String {
return "game: " + item.@label;
}
private function xlistChanged(event:CollectionEvent):void {
trace("xlistChanged(" + event +")");
all.text = "All games: " + _xlist.game.length();
full.text = "Full games: " + _xlist.game.(user.length() == 3).length();
vacant.text = "Vacant games: " + _xlist.game.(user.length() < 3).length();
}
]]>
</mx:Script>
<mx:Label id="all" text="All games"/>
<mx:Label id="full" text="Full games"/>
<mx:Label id="vacant" text="Vacant games"/>
<mx:List id="list" labelFunction="gameLabel"/>
MyTest.mxml (cliquez sur les boutons à XML du changement):
private function changeXML1():void {
games = <games>
<game label="1">
<user/>
<user/>
<user/>
</game>
<game label="2">
<user/>
<user/>
</game>
<game label="3">
<user/>
<user/>
<user/>
</game>
</games>;
}
private function changeXML2():void {
games = <games>
<game label="A">
<user/>
<user/>
<user/>
</game>
<game label="B">
<user/>
<user/>
</game>
<game label="C">
</game>
</games>;
}
]]>
</mx:Script>
<mx:XML id="games">
<games>
<game label="X">
<user/>
<user/>
</game>
<game label="Y">
<user/>
<user/>
</game>
</games>
</mx:XML>
<mx:Button label="Change XML 1" click="changeXML1()"/>
<mx:Button label="Change XML 2" click="changeXML2()"/>
<my:Games xlist="{games.game}"/>
S'il vous plaît me conseiller ce qui est faux.
Cordialement, Alex
Mise à jour: édité Games.mxml comme suggéré par clownbaby - ne fonctionne toujours pas (xlistChanged est jamais invoqué):
<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:my="*" creationComplete="onCreationComplete(event)">
<mx:Script>
<![CDATA[
import mx.events.*;
private var _xlist:XMLList;
[Bindable]
public function get xlist():XMLList {
return _xlist;
}
public function set xlist(x:XMLList):void {
_xlist = x;
list.dataProvider = x;
trace("\n set: " + x);
}
private function gameLabel(item:Object):String {
return "game: " + item.@label;
}
private function onCreationComplete(event:FlexEvent):void {
list.dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE, xlistChanged);
}
private function xlistChanged(event:CollectionEvent):void {
all.text = "All games: " + xlist.length();
full.text = "Full games: " + xlist.(user.length() == 3).length();
vacant.text = "Vacant games: " + xlist.(user.length() < 3).length();
}
]]>
</mx:Script>
<mx:Label id="all" text="All games"/>
<mx:Label id="full" text="Full games"/>
<mx:Label id="vacant" text="Vacant games"/>
<mx:List id="list" labelFunction="gameLabel"/>
</mx:VBox>
La solution
Deux choses:
1) La raison pour laquelle votre événement ne se déclenche pas parce que vous ajoutez l'auditeur après avoir défini _xlist
.
2) Vous ne devriez pas ajouterez un écouteur d'événements au sein de votre setter de toute façon. Vous devez l'ajouter sur initialize ou d'événements creationComplete de votre composant VBox.
EDIT
Bon, après avoir regardé à nouveau votre code, je peux voir le problème ... donc juste quelques petites choses.
3) Pourquoi vous nommez un init
de méthode, quand il est appelé creationComplete
? Vous devriez prendre l'habitude de nommer les méthodes de façon appropriée. Par exemple, la méthode qui est appelée sur creationComplete
devrait être nommé: onCreationComplete
ou handleCreationComplete
De cette façon, vous saurez ce que votre code fait 6 mois sur la route
4) Ceci est votre principal problème: Vous utilisez les getters / setters en conséquence. Si vous avez un setter, vous devez également mettre en œuvre un getter (sauf si vous avez un champ d'écriture seule). Plus important encore, vous devez utiliser le getter pour accéder à vos données. Dans la méthode xListChanged
vous n'utilisez pas le poseur que vous avez défini, donc rien obtient le dit _xlist
réellement changé. En tant que tel, vous devez changer votre code:
private var _xlist:XMLListCollection;
[Bindable]
public function get xlist():XMLListCollection { return this._xlist; }
public function set xlist(value:XMLListCollection):void
{
this._xlist = value;
}
Chaque fois que vous voulez _xlist
d'accès, utilisez le getter. Par exemple, changer le fournisseur de données de votre composant List
être {xlist}
. Et la méthode xListChanged
devrait utiliser le getter. xlist
au lieu d'accéder directement au _xlist
membre
Autres conseils
Pourquoi ne pas faire ceci:
fonction publique ensemble XList (x: XMLList): void {
_xlist = new XMLListCollection(x); _all.label = 'All (' + _xlist.length + ')'; var full:XMLList = _xlist.source.game.(user.length() == 3); _full.label = 'Full (' + full.length() + ')'; var free:XMLList = _xlist.source.game.(user.length() < 3); _free.label = 'Free (' + free.length() + ')';
}
Vous n'avez pas besoin d'écoute si la seule façon de régler la variable _xlist locale est en définissant la propriété de xlist.