2008-10-08 18 views
6

Ich möchte eine wiederverwendbare Schaltfläche haben, die für einen von vielen verschiedenen Rückrufen registriert werden kann, die von einer externen Quelle bestimmt werden. Wenn ein neuer Rückruf festgelegt ist, möchte ich den alten entfernen. Ich möchte auch in der Lage sein, den Rückruf jederzeit extern zu löschen.Gibt es eine Möglichkeit, unbekannte Ereignislistener von Objekten zu entfernen?

public function registerButtonCallback(function:Function):void 
{ 
    clearButtonCallback(); 

    button.addEventListener(MouseEvent.CLICK, function, false, 0, true); 
} 

public function clearButtonCallback():void 
{ 
    if (button.hasEventListener(MouseEvent.CLICK) == true) 
    { 
    // do something to remove that listener 
    } 
} 

Ich habe hier gesehen Vorschläge innerhalb der Callback „arguments.callee“ zu verwenden, aber ich will nicht, dass die Funktionalität an die Callback gebunden haben - zum Beispiel, könnte ich mag in der Lage sein Klicken Sie zweimal auf die Schaltfläche.

Vorschläge?

Antwort

8

Ich nehme an, dass Sie nur eine Callback-Funktion zu einem bestimmten Zeitpunkt möchten. Wenn die teh Fall ist, dann warum nicht eine einzelne Rückruffunktion mit dem Click-Ereignisse zugeordnet ist, auf der Schaltfläche, die selbst eine Funktion aufgerufen und hat diese Funktion einstellbar sein ...

<mx:Button click="doCallback()" .../> 

public var onClickFunction:Function = null; 
private function doCallback():void 
{ 
    if (onClickFunction != null) 
    { 
     onClickFunction(); // optionally you can pass some parameters in here if you match the signature of your callback 
    } 
} 

Ein Verbraucher Ihrer Kontrolle, die Ihre Schaltfläche Häuser würde die onClickFunction mit der entsprechenden Funktion festlegen. Tatsächlich könnte man es so oft einstellen, wie man möchte.

Wenn Sie einen Schritt weiter gehen wollten, könnten Sie die AS3 Button-Klasse ableiten und alles darin einbetten.

+0

Gotcha. Weißt du, ich glaube, ich habe das angefangen und mich aus irgendeinem Grund dagegen entschieden, an den ich mich nicht erinnere. So oder so, Ihre Annahme ist richtig und es ist eine gute Möglichkeit, das zu tun, was ich beabsichtigt habe. Vielen Dank. –

+0

Großartig, froh, dass ich helfen konnte. Wenn Sie dies als die Antwort markieren, bekomme ich auch ein paar Rep-Punkte :-) – Simon

3

Speichern Sie den Listener als Prop. Wenn ein weiteres Ereignis hinzugefügt wird, überprüfen Sie, ob der Listener vorhanden ist, und rufen Sie dann removeEventListener auf.

Alternativ können Sie die addEventListener-Methode der Schaltfläche überschreiben. Wenn addEventListener aufgerufen wird, speichern Sie den Abschluss, bevor Sie ihn zum Ereignis in einem Dictionary-Objekt hinzufügen. Wenn addEventListener erneut aufgerufen wird, entfernen Sie sie:


var listeners:Dictionary = new Dictionary();

override public function addEventListener(type : String, listener : Function, useCapture : Boolean = false, priority : int = 0, useWeakReference : Boolean = false) : void {

if(listeners[ type ]) { 

    if(listeners[ type ] [ useCapture ] { 

     //snip... etc: check for existence of the listener 

     removeEventListener(type, listeners[ type ] [ useCapture ], useCapture); 

     listeners[ type ] [ useCapture ] = null; 

     //clean up: if no listeners of this type exist, remove the dictionary key for the type, etc... 

    } 

    } 

    listeners[ type ] [ useCapture ] = listener; 

    super.addEventListener(type, listener, useCapture, priority, useWeakReference); 

}; 

+0

Keine dieser Optionen tun, was die Frage stellt, nämlich einen UNKOWN-Ereignis-Listener von einem vorhandenen EventDispatcher-Objekt abzurufen. Diese Methoden speichern nur einen KNOWN-Listener, bevor er dem Objekt hinzugefügt wird. Wenn der Listener nicht bekannt ist und gespeichert wird, bevor er dem Objekt hinzugefügt wird, gibt es keine Möglichkeit, ihn später wieder abzurufen. – Triynko

+3

Aber sie bieten Möglichkeiten, die unbekannten Ereignis-Listener bekannt zu machen, was eine andere Möglichkeit ist, das Problem anzugehen. – voidstate

1

Etwas, was ich tun möchte, ist eine dynamische globale Klasse verwenden und einen schnellen Hinweis auf die Listener-Funktion Inline hinzuzufügen. Dies setzt voraus, dass Sie möchten, dass die Listener-Funktion in der addEventListener-Methode wie ich funktioniert. Auf diese Weise können Sie removeEventListener innerhalb der addEventListener verwenden :)

dies ausprobieren:

package { 

import flash.display.Sprite; 
import flash.events.Event; 
import flash.text.TextField; 

[SWF(width="750", height="400", backgroundColor="0xcdcdcd")] 
public class TestProject extends Sprite 
{ 
    public function TestProject() 
    { 
     addEventListener(Event.ADDED_TO_STAGE, Global['addStageEvent'] = function():void { 
      var i:uint = 0; 
      //How about an eventlistener inside an eventListener? 
      addEventListener(Event.ENTER_FRAME, Global['someEvent'] = function():void { 
       //Let's make some text fields 
       var t:TextField = new TextField(); 
        t.text = String(i); 
        t.x = stage.stageWidth*Math.random(); 
        t.y = stage.stageHeight*Math.random(); 
       addChild(t); 
       i++; 
       trace(i); 
       //How many text fields to we want? 
       if(i >= 50) { 
        //Time to stop making textFields 
        removeEventListener(Event.ENTER_FRAME, Global['someEvent']); 
        //make sure we don't have any event listeners 
        trace("hasEventListener(Event.ENTER_FRAME) = "+hasEventListener(Event.ENTER_FRAME));  
       } 
      }); 

      //Get rid of the listener 
      removeEventListener(Event.ADDED_TO_STAGE, Global['addStageEvent']); 
      trace('hasEventListener(Event.ADDED_TO_STAGE) = '+hasEventListener(Event.ADDED_TO_STAGE)); 

     }); 
    } 

} 

}

// looky hier! Dies ist das wichtige Bit dynamische Klasse Global {}

Das Geheimnis ist die dynamische Klasse Global. Damit können Sie dynamisch Eigenschaften zur Laufzeit hinzufügen.

4

Nein. Sie müssen einen Verweis auf den Listener halten, um ihn zu entfernen. Sofern Sie nicht zuvor einen Verweis auf die Listener-Funktion speichern, ist keine dokumentierte öffentliche Methode verfügbar, um einen solchen Verweis von einem EventDispatcher abzurufen.

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void 
dispatchEvent(event:Event):Boolean 
hasEventListener(type:String):Boolean 
removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void 
willTrigger(type:String):Boolean 

Wie Sie sehen können, gibt es zwei Methoden, um Ihnen zu sagen, ob eine Art von Veranstaltung einen Zuhörer hat registriert oder einem seiner Eltern hat ein Zuhörer registriert, aber keine dieser Methoden tatsächlich eine Liste der registrierten Hörer zurückkehren .

Jetzt bitte gehen Sie belästigen Adobe für das Schreiben solch eine nutzlose API.Im Grunde geben sie Ihnen die Möglichkeit zu wissen, "ob" sich der Ereignisfluss geändert hat, aber sie geben Ihnen keine Möglichkeit, etwas mit diesen Informationen zu tun!

2

Ich habe eine Unterklasse namens EventCurb für diesen Zweck geschrieben, siehe meine blog hier oder einfügen unten.

package 
{ 
    import flash.events.EventDispatcher; 
    import flash.utils.Dictionary; 
    /** 
    * ... 
    * @author Thomas James Thorstensson 
    * @version 1.0.1 
    */ 
    public class EventCurb extends EventDispatcher 
    { 
     private static var instance:EventCurb= new EventCurb(); 
     private var objDict:Dictionary = new Dictionary(true); 
     private var _listener:Function; 
     private var objArr:Array; 
     private var obj:Object; 

     public function EventCurb() { 
     if(instance) throw new Error("Singleton and can only be accessed through Singleton.getInstance()"); 
     } 

     public static function getInstance():EventCurb { 
     return instance; 
     } 

     override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void 
     { 
     super.addEventListener(type, listener, useCapture, priority, useWeakReference); 
     } 

     override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void 
     { 
     super.removeEventListener(type, listener, useCapture); 
     } 

     public function addListener(o:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void { 
     // the object as key for an array of its event types 
     if (objDict[o] == null) objArr = objDict[o] = []; 
     for (var i:int = 0; i < objArr.length; i++) { 
      if (objArr[i].type == type) 
      trace ("_______object already has this listener not adding!") 
      return 
     } 
     obj = { type:type, listener:listener } 
     objArr.push(obj); 
     o.addEventListener(type, listener, useCapture, priority, useWeakReference); 
     } 

     public function removeListener(o:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false):void { 
     // if the object has listeners (ie exists in dictionary) 
     if (objDict[o] as Array !== null) { 
      var tmpArr:Array = []; 
      tmpArr = objDict[o] as Array; 
      for (var i:int = 0; i < tmpArr.length; i++) { 
       if (tmpArr[i].type == type) objArr.splice(i); 
      } 

      o.removeEventListener(type, listener, useCapture); 
      if (tmpArr.length == 0) { 
       delete objDict[o] 
      } 
     }else { 
      trace("_______object has no listeners"); 
     } 
     } 

     /** 
     * If object has listeners, returns an Array which can be accessed 
     * as array[index].type,array[index].listeners 
     * @param o 
     * @return Array 
     */ 
     public function getListeners(o:EventDispatcher):Array{ 
     if (objDict[o] as Array !== null) { 
      var tmpArr:Array = []; 
      tmpArr = objDict[o] as Array; 
      // forget trying to trace out the function name we use the function literal... 
      for (var i:int = 0; i < tmpArr.length; i++) { 
       trace("_______object " + o + " has event types: " + tmpArr[i].type +" with listener: " + tmpArr[i].listener); 
      } 
      return tmpArr 

     }else { 
      trace("_______object has no listeners"); 
      return null 
     } 

     } 

     public function removeAllListeners(o:EventDispatcher, cap:Boolean = false):void { 
     if (objDict[o] as Array !== null) { 
      var tmpArr:Array = []; 
      tmpArr = objDict[o] as Array; 
      for (var i:int = 0; i < tmpArr.length; i++) { 
       o.removeEventListener(tmpArr[i].type, tmpArr[i].listener, cap); 
      } 
      for (var p:int = 0; p < tmpArr.length; p++) { 
       objArr.splice(p); 
      } 

      if (tmpArr.length == 0) { 
       delete objDict[o] 
      } 
     }else { 
      trace("_______object has no listeners"); 
     } 
     } 
    } 
} 
0
private function callFunction(function:Function):void 
{ 
    checkObject(); 
    obj.addEventListener(MouseEvent.CLICK,function); 
} 

private function checkObject():void 
{ 
    if(obj.hasEventListener(MouseEvent.CLICK)) 
    { 
     //here remove that objects 
    } 
} 
Verwandte Themen