实现 IEventDispatcher 的类不能使用事件元数据标记

发布于 2024-11-04 21:19:32 字数 3269 浏览 1 评论 0 原文

好的,Flex 大师,我们有以下类

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;
            }
       }

    }

,并且我们有以下 MXML 标记:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
           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>

如果您运行这些,您会注意到 MXML 组件无法听到该事件。问题很简单,是否有某种方法可以让 Event-metadata 标签在不扩展 EventDispatcher 的情况下工作?我想保持这个类的独立性并尽可能地使用对象组合。

不,我不想在 MXML 文件中使用 ActionScript addEventListener。它不会告诉开发人员任何类似于旧事件元数据标记的信息,而且,这不是本示例的重点。 :)

希望有人能够启发事件元数据标签在幕后的作用。

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/2009" 
           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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

脸赞 2024-11-11 21:19:32

好的。为了使您的代码正常工作,您应该更改您的主类,如下所示:

<?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>

问题是您没有设置正确分派事件的对象。在您的情况下,该对象仍然是主应用程序类。为了达到你的目标,你应该重新创建你的 IndependentClass ,如下所示:

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");
    }
}
}

我已经评论了构造函数中执行所有魔法的行。更多详细信息请参阅 官方文档

因此,您的主类将如下所示:

<?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>

那么 [Event] 元标记又如何呢?它只不过是一个编译时注释,可帮助编译器验证 MXML 标签属性。此元标记的另一个用途是通过 IDE 提供事件代码补全(在 MXML 中和在您键入 addEventListener 时在 ActionScript 中)。它对运行时没有任何影响。

PS Jeffry 说得对,你应该扩展 EventDispatcherIEventDispatcher 的用途是如果您的类继承了某个不是从 EventDispatcher 派生的其他类。这种情况下可以使用组合来解决事件派发的问题。在您的情况下,您的 IndependentClass 没有任何不从 EventDispatcher 继承的要求。

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.

无声静候 2024-11-11 21:19:32

无需事件元数据标记即可工作
扩展EventDispatcher

据我所知,事件元数据标签只做两件事。它告诉代码暗示组件可以调度事件;或者用于生成 ASDoc。我希望您能够在不扩展 EventDispatcher 的情况下使用元数据标签;但是,我不相信您的组件在不扩展 EventDispatcher 或创建您自己的事件调度程序系统的情况下能够调度事件。我认为 AS3 Signals 是另一种事件调度系统。

我不想使用 ActionScript
MXML 文件中的 addEventListener。它
没有告诉开发人员任何信息
就像旧的事件元数据标签一样,

addEventListener 方法是一种向组件添加事件侦听器的方法。
元数据标记是一种告诉代码暗示该组件可以调度事件的方法。
它们的目的截然不同;使用其中之一并不否定对另一个的需要。

我相信这可以解决您的问题。我个人的方法是,如果类需要调度事件,则扩展 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文