开发者

Class implementing IEventDispatcher cannot use Event metadata tag

Okay Flex gurus, we have following class

package
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.IEventDispatcher;

    import mx.controls.Alert;
    import mx.core.IMXMLObject;

    [Event(name="progressReady", type="flash.events.Event")]
    public class IndependentClass implements IMXMLObject, IEventDispatcher{
            public var dispatcher:IEventDispatcher;

            public function initialized(document:Object, id:String):void{
                    dispatcher = document as EventDispatcher;
                    addEventListener("progressReady", progressReadyListener);
            }

            public function progressReadyListener(e:Event):void{
                    Alert.show("progressReadyListener inside");
            }

            public function click():void{
                    dispatchEvent(new Event("progressReady", true));
            }

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

            public function dispatchEvent(event:Event):Boolean{
                    if(dispatcher != null){
                            return dispatcher.dispatchEvent(event);
                    }
                    return false;
            }

            public function hasEventListener(type:String):Boolean{
                    if(dispatcher != null){
                            return dispatcher.hasEventListener(type);
                    }
                    return false;
            }

            public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void{
                    if(dispatcher != null){
                            dispatcher.removeEventListener(type, listener, useCapture);
                    }
            }

            public function willTrigger(type:String):Boolean{
                    if(dispatcher != null){
                            return dispatcher.willTrigger(type);
                    }
                    return false;
            }
       }

    }

And we have following MXML markup:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2开发者_运维百科009" 
           xmlns:s="library://ns.adobe.com/flex/spark" 
           xmlns:mx="library://ns.adobe.com/flex/mx" 
           xmlns:local="*">

<fx:Script>
    <![CDATA[
        import mx.controls.Alert;
        protected function progressHandler():void{
            Alert.show("progressHandler outside");
        }
    ]]>
</fx:Script>

<fx:Declarations>
    <local:IndependentClass id="ic" progressReady="progressHandler()"/>
</fx:Declarations>

<s:Button click="{ic.click()}"/>
</s:Application>

If you run these, you'll notice that the MXML-component can't hear the event. The question is simple, is there some way of getting the Event-metadata tag to work WITHOUT extending EventDispatcher? I would like to keep this class independent and use object composition as much as possible.

And no, I don't want to use ActionScript addEventListener in the MXML-file. It doesn't tell the developer anything like good old Event metadata tag, and besides, that is not the point of this example. :)

Hopefully someone can enlighten what the event metadata tag does behind the curtains.


Ok. To make your code working ypu should change your main class like the following:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="*" xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark" creationComplete="init()">

    <fx:Script>
    <![CDATA[
        import mx.controls.Alert;

        protected function progressHandler():void
        {
            Alert.show("progressHandler outside");
        }

        protected function init():void
        {
            addEventListener("progressReady", progressReadyHandler);
        }

        private function progressReadyHandler(event:Event):void
        {
            progressHandler();
        }
    ]]>
    </fx:Script>

    <fx:Declarations>
        <local:IndependentClass id="ic" />
    </fx:Declarations>

    <s:Button click="{ic.click()}" />
</s:Application>

The problem is you didn't set object which dispatches events properly. In your case this object is still main application class. To reach your aim your should recreate your IndependentClass like the following:

package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;

import mx.controls.Alert;

[Event(name="progressReady", type="flash.events.Event")]
public class ProperIndependentClass implements IEventDispatcher
{
    public function ProperIndependentClass()
    {
        // This line initialized dispatching making this object target and currentTarget of the event
        dispatcher = new EventDispatcher(this);
        addEventListener("progressReady", progressReadyListener);
    }

    private var dispatcher:EventDispatcher;

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

    public function click():void
    {
        dispatchEvent(new Event("progressReady", true));
    }

    public function hasEventListener(type:String):Boolean
    {
        return dispatcher.hasEventListener(type);
    }

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

    public function willTrigger(type:String):Boolean
    {
        return dispatcher.willTrigger(type);
    }

    public function dispatchEvent(evt:Event):Boolean
    {
        return dispatcher.dispatchEvent(evt);
    }

    public function progressReadyListener(e:Event):void
    {
        Alert.show("progressReadyListener inside");
    }
}
}

I've commented the line in constructor which performs all the magic. More details are available in official documentation.

So your main class will look like the following:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:local="*" xmlns:mx="library://ns.adobe.com/flex/mx"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Script>
    <![CDATA[
        import mx.controls.Alert;

        protected function progressHandler():void
        {
            Alert.show("progressHandler outside");
        }
    ]]>
    </fx:Script>

    <fx:Declarations>
        <local:ProperIndependentClass id="ic" progressReady="progressHandler()" />
    </fx:Declarations>

    <s:Button click="{ic.click()}" />
</s:Application>

And what about [Event] metatag. It is nothing than a compile time annotation which helps compiler to validate MXML tags attributes. Another usage of this metatag is offering events code completion by IDE (both in MXML and in ActionScript when you're typing addEventListener). It hasn't any influence at runtime.

P.S. And Jeffry is right saying you should just extend EventDispatcher. The purpose of IEventDispatcher is if your class inherits some other class which is not derived from EventDispatcher. In this case you can use composition to solve the problem of event dispatching. In your case your IndependentClass hasn't any requirements to not inherit from EventDispatcher.


Event-metadata tag to work WITHOUT extending EventDispatcher

As far as I know, the event metadata tag does only two things. It tells code hinting that the component may dispatch the event; or it is used for generating ASDocs. I would expect you'll be able to use the metadata tag without extending EventDispatcher; however I do not believe your component will be able to dispatch an event without extending EventDispatcher or creating your own Event Dispatcher system. I think AS3 Signals is an alternative Event Dispatching System.

I don't want to use ActionScript addEventListener in the MXML-file. It doesn't tell the developer anything like good old Event metadata tag,

The addEventListener method is a way to add an event listener to a component.
The metadata tag is a way to tell code hinting that this component may dispatch the event.
They serve very different purposes; and using one does not negate the need for the other.

I believe that addresses your questions. My personal approach is to extend EventDispatcher if the class needs to dispatch events.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜