So my problem is the selectedIndex isn't updated when i use nextSlide() and prevSlide(), which are executed when i click on two buttons. SelectedIndex works when i click on the elements in the List. What am i doing wrong? do i have to dispatch some events? Are there any tricks to doing it with buttons?
This is my playlist class
public class Playlist extends List
{
private var dispatcher:Dispatcher;
public function Playlist()
{
super();
this.dragEnabled = true;
this.dragMoveEnabled = true;
this.dropEnabled = true;
this.allowMultipleSelection = true;
this.dispatcher = new Dispatcher();
}
public function handleSelection(event:PlaylistEvent):void
{
if (event.type == PlaylistEvent.ITEMS_SELECTED){
selectItem(event.index, event.count);
selectedIndex = event.index;
}
}
private function selectItem(index:Number, count:Number):void
{
var tempArray:Array = this.dataProvider.toArray();
var indiceVector:Vector.<int> = new Vector.<int>();
var itemVector:Vector.<Object> = new Vector.<Object>();
var n:int = 1;
for (var i:int=0;i<tempArray.length;i++){
var item:PlaylistItem = tempArray[i];
if (i<index) deselectItem(item);
else if (i<index+count) {
item.Selected=true;
indiceVector[count-n] = i;
itemVector[count-n++] = item;
}
else deselectItem(it开发者_如何学Goem);
}
selectedItems = itemVector;
selectedIndices = indiceVector;
}
private function deselectItem(item:PlaylistItem):void
{
item.Selected = false;
}
public function nextSlide():void
{
if (dataProvider.length == 0) return;
var index:int = selectedIndex;
if (index < 0) {
var event1:PlaylistEvent = new PlaylistEvent(PlaylistEvent.ITEMS_SELECTED, 0, 1);
dispatcher.dispatchEvent(event1);
return;
}
var item:PlaylistItem = PlaylistItem(dataProvider.getItemAt(index));
if (index < dataProvider.length-1) {
trace("going to index", index+1);
var event:PlaylistEvent = new PlaylistEvent(PlaylistEvent.ITEMS_SELECTED, index+1, 1);
dispatcher.dispatchEvent(event);
return;
}
}
public function previousSlide():void
{
if (dataProvider.length == 0) return;
var index:int = selectedIndex;
if (index < 0) {
var event1:PlaylistEvent = new PlaylistEvent(PlaylistEvent.ITEMS_SELECTED, 0, 1);
dispatcher.dispatchEvent(event1);
return;
}
var item:PlaylistItem = PlaylistItem(dataProvider.getItemAt(index));
if (index > 0) {
var event:PlaylistEvent = new PlaylistEvent(PlaylistEvent.ITEMS_SELECTED, index-1, 1);
dispatcher.dispatchEvent(event);
return;
}
}
}
}
This is my mate EventMap
<?xml version="1.0" encoding="utf-8"?>
<mate:EventMap xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mate="http://mate.asfusion.com/"
xmlns:air="de.websector.mate.extensions.air.*">
<fx:Script>
<![CDATA[
import components.Playlist;
import events.PlaylistEvent;
import mx.controls.Alert;
import mx.events.*;
import mx.logging.*;
import mx.logging.Log;
import spark.components.Application;
private var logger:ILogger;
private function initLogger():void{
logger = Log.getLogger("MainEventMap");
trace("started init maineventmap");
}
]]>
</fx:Script>
<fx:Declarations>
<mate:EventHandlers type="{FlexEvent.APPLICATION_COMPLETE}">
<mate:InlineInvoker method="initLogger"/>
<mate:ObjectBuilder generator="{MainManager}"/>
<mate:EventAnnouncer type="{InitEvent.SYSTEM_INIT_COMPLETE}" />
</mate:EventHandlers>
<mate:Injectors target="{Playlist}">
<mate:PropertyInjector targetKey="dataProvider" source="{MainManager}" sourceKey="playlistItems" />
</mate:Injectors>
<mate:Injectors target="{MainManager}">
<mate:PropertyInjector targetKey="playlist" source="{Playlist}" />
</mate:Injectors>
<!-- Playlist events! __________________________________________________________________________________________________-->
<mate:EventHandlers type="{PlaylistEvent.ITEMS_SELECTED}">
<mate:MethodInvoker generator="{Playlist}" method="handleSelection" arguments="{event}" />
</mate:EventHandlers>
</fx:Declarations>
</mate:EventMap>
Mate isn't able to populate your private dispatcher variable with a reference to its event bus, so the event map never "hears" the event you are dispatching on it, and can't invoke your method.
This seems like a silly way to invoke a method on the same component, and I think this is a sign that you know that you ought to separate the logic in some way. What I'd suggest is that you have a Presentation Model that contains the dataprovider and selectedIndex, and inject a reference to that. Then, your List will bind to the dataprovider and selectedIndex. The pm can listen for events on the bus to maintain selectedIndex, or you can operate it directly from the View component.
That way, when you realize it's a bit problematic to have a List subclass that has buttons in it, you can attach the new Group subclass that has a List and buttons in it without any problem.
For an example of how to properly inject the event bus (that conveniently shows how to use a PM), check out http://www.developria.com/2010/05/refactoring-with-mate.html. It looks like you've got a good start on understanding the event bus, but you might want to get a bit more detail by looking at http://www.developria.com/2010/05/pass-the-eventdispatcher-pleas.html .
As someone pointed out on #Flex (irc://irc.freenode.net/flex), the mistake is using MethodInvoker as it constructs a new instance of the class and then running the handleSelection method on said instance. I solved this problem by injecting the instance of playlist into the EventMap and using InlineInvoker.
<mate:EventHandlers type="{PlaylistEvent.ITEMS_SELECTED}">
<mate:InlineInvoker method="{playlist.handleSelection}" arguments="{event}" />
</mate:EventHandlers>
So the problem was in the use of the mate framework, not in Flex or databinding or eventdispatching.
精彩评论