【问题标题】:Flex: Expose component's existing events with new nameFlex:以新名称公开组件的现有事件
【发布时间】:2011-01-07 22:26:08
【问题描述】:

我创建了一个 flex 组件,其中包含多个内置 (mx) 组件,例如列表框和组合框。我的组件依赖外部数据,我需要暴露 ComboBox.enter 和 List.click 等事件来获取某些数据。

我想知道是否有任何简单的方法可以做到这一点,而无需创建我自己的自定义事件处理程序。我只是试图以不同的名称公开这些事件,以便在使用我的组件时,我可以执行以下操作:

<?xml version="1.0" encoding="utf-8"?>
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" xmlns:com="com.*">
    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            [Bindable]
            public var dp:ArrayCollection = new ArrayCollection(["Apple","B","C","D","E","F","G","H","I","J","K"]);
        ]]>
    </mx:Script>
    <mx:ComboBox dataProvider="{dp}"/>
    <mx:List/>
</mx:Canvas>

我希望能够按如下方式使用它:

<com:MyComponent listBoxChanged="getExternalData(event)" comboBoxClick="comboBoxClicked(event)"/>

我想我想要做的是将组件中的事件传播到父组件,事件被重命名。

【问题讨论】:

    标签: apache-flex events custom-controls components


    【解决方案1】:

    您可以通过创建一个类来重定向事件,从而用最少的代码做到这一点。您想要的是一个接受源事件分派器、源事件名称、目标事件名称和目标事件分派器的类。假设您将此 EventRedispatcher 称为。这是一个完整的例子。

    EventRedispatcherTest.mxml:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application 
        xmlns:mx="http://www.adobe.com/2006/mxml"
        xmlns:local="*" 
        layout="horizontal" 
        width="100%" 
        height="100%">
    
        <mx:Script>
            <![CDATA[
                import mx.events.ListEvent;
    
                private function doLog(event:Event):void {
    
                    var extraInfo:String = "";
    
                    var listEvent:ListEvent = event as ListEvent;
                    if (listEvent != null && listEvent.itemRenderer != null) {
                        extraInfo = String(listEvent.itemRenderer.data);
                    }
    
                    var mouseEvent:MouseEvent = event as MouseEvent;
                    if (mouseEvent != null) {
                        extraInfo = mouseEvent.stageX + "," + mouseEvent.stageY;
                    }
                    log.text += event.target.id + "." + event.type + ":" + extraInfo + "\n";
                }
            ]]>
        </mx:Script>
        <mx:TextArea width="300" height="100%" id="log" />
    
        <local:EventRedispatcherComponent 
            id="component1" 
            listboxChange="doLog(event)" 
            comboboxChange="doLog(event)" 
            buttonClick="doLog(event)" 
            />
    
        <local:EventRedispatcherComponent 
            id="component2" 
            listboxChange="doLog(event)" 
            comboboxChange="doLog(event)" 
            buttonClick="doLog(event)" 
            />
    </mx:Application>
    

    EventRedispatcherComponent.mxml:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:HBox 
        xmlns:mx="http://www.adobe.com/2006/mxml" 
        creationComplete="init()"
        borderStyle="solid"
        borderColor="#FF0000" 
        width="300" 
        height="200">
    
        <mx:Metadata> 
            [Event(name="comboboxChange", type="mx.events.ListEvent")] 
            [Event(name="listboxChange", type="mx.events.ListEvent")] 
            [Event(name="buttonClick", type="flash.events.MouseEvent")] 
        </mx:Metadata> 
    
        <mx:Script>
        <![CDATA[
    
            private function init():void
            {       
                // TODO: Create EventRedispatcher class :-)
                new EventRedispatcher(combobox, "change", this, "comboboxChange");
                new EventRedispatcher(listbox, "change", this, "listboxChange");
                new EventRedispatcher(button, "click", this, "buttonClick");
            }
        ]]>
        </mx:Script>
        <mx:ComboBox id="combobox" dataProvider="{[1, 2, 3]}" />
        <mx:List id="listbox" dataProvider="{[1, 2, 3]}" />
        <mx:Button id="button" label="Text" />
    </mx:HBox>
    

    EventRedispatcher.as

    package
    {
        import flash.events.Event;
        import flash.events.EventDispatcher;
        import flash.utils.describeType;
        import flash.utils.getDefinitionByName;
        import flash.utils.getQualifiedClassName;
    
        public class EventRedispatcher
        {
            private var targetDispatcher:EventDispatcher;
            private var targetName:String;
    
            private static var propertiesByEventType:Object = new Object();
    
            public function EventRedispatcher(sourceDispatcher:EventDispatcher, sourceName:String, targetDispatcher:EventDispatcher, targetName:String)
            {
                this.targetDispatcher = targetDispatcher;
                this.targetName = targetName;
    
                sourceDispatcher.addEventListener(sourceName, redispatch); 
            }
    
            private function redispatch(event:Event):void {
                var newEvent:Event = copyEvent(event);
                targetDispatcher.dispatchEvent(newEvent);
            }
    
            private function copyEvent(event:Event):Event {
                var className:String = getQualifiedClassName(event);
                var newEvent:Event = new (getDefinitionByName(className))(targetName);          
    
                var properties:Array = getPropertiesForClass(event, className);
    
                for each(var propertyName:String in properties) {
                    newEvent[propertyName] = event[propertyName];
                }
    
                return newEvent;                                    
            }
    
            private function getPropertiesForClass(event:Event, className:String):Array {
    
                var properties:Array = propertiesByEventType[className];
                if (properties != null) {
                    return properties;
                }
    
                var description:XML = describeType(event);
                properties = new Array();
    
                for each(var accessor:XML in description.accessor.(@access == 'readwrite')) {
                    properties.push(accessor.@name);
                } 
    
                for each(var variable:XML in description.variable) {
                    properties.push(variable.@name);
                } 
    
                propertiesByEventType[className] = properties;
                return properties;
            }
        }
    }
    

    【讨论】:

    • 听起来不太聪明,但如果我知道该怎么做,我就不会问这个问题了。
    • @FlashFlex:我更新了示例,现在它已经完成,包含完整的组件、完整的测试应用程序和 EventRedispatcher 的实现。
    • 谢谢,这就是我想要做的。我有自己的事件 EventRedispatcher 类,但它将旧事件包装在自定义事件中。这好多了。
    【解决方案2】:

    这应该不会太难。

    首先,您需要确定您的事件(listBoxChanged、comboBoxClick)是否需要与它们一起存储数据。 如果是这种情况,则使用存储要传递的数据的变量创建 2 个自定义事件(每个事件一个)。

    在MyComponent 中,需要为ComboBox 点击事件和List change 事件添加监听器。在您的方法处理程序中,调度您刚刚创建的类型的事件。

    不要忘记在组件顶部添加 2 个 Event 元标记,以便在 listBoxChanged 和 comboBoxClick 上自动完成

    【讨论】:

    • 是的,但我想用不同的名称调度事件,因为例如多个组件都有一个“click”或“creationComplete”事件。我想要更清晰的内容,例如“listBoxClicked”或“comboBoxCreationComplete”。我已经知道如何调度事件。也许你已经回答了我的问题,但我不太明白如何回答。
    • @FlashFlex - 您在此处的评论澄清了您的问题,您应该编辑您的问题并将这些详细信息添加到其中。
    【解决方案3】:

    您可以通过组件元数据做到这一点:

    <mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" xmlns:com="com.*">
    
        <mx:Metadata> 
            [Event(name="myListChange", type="mx.event.ListChange")] 
        </mx:Metadata> 
    
        <mx:Script>
            <![CDATA[
                import mx.collections.ArrayCollection;
                [Bindable]
                public var dp:ArrayCollection = new ArrayCollection(["Apple","B","C","D","E","F","G","H","I","J","K"]);
    
                private function onListEventChange(event:ListEvent):void
                {         
                      //create your own event if you need to pass data with the event.    
                      dispatchEvent(new Event("myListChange"));
                }
            ]]>
        </mx:Script>
        <mx:ComboBox dataProvider="{dp}"/>
        <mx:List change="onListEventChange(event)/>
    </mx:Canvas>
    

    或者你可以只冒泡事件并在父组件上监听它们,尽管我不推荐这样做。

    【讨论】:

      【解决方案4】:

      Event.type 是只读的,因此您不能使用新名称调度相同的确切事件。因此,您需要在新发送的事件中包装或复制数据。 (通常你会使用clone,但这会使事件类型保持不变。)

      熊正在复制单个事件类型,但如果你有一个有限的集合,你可以做到。

      public function EventRedispatcher(src:EventDispatcher, srcType:String, dest:EventDispatcher, destType:String) {
          src.addEventListener(srcType, function(e:Event):void {
             var clone:Event = cloneEvent(e, destType);
             dest.dispatchEvent(clone);
          });
      }
      
      // pick your favorite factoryish idiom here
      private function cloneEvent(e:Event, newType:String):Event {
          if (e is MouseEvent) {
             var me:MouseEvent = MouseEvent(e);
             return new MouseEvent(newType, me.bubbles, me.cancelable, me.localX, ...);
          }
          if (e is ...) {}
      
          // default
          return new Event(newType, e.bubbles, e.cancelable);
      }
      

      【讨论】:

        猜你喜欢
        • 2010-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多