Flex: Показать существующие события компонента с новым именем - PullRequest
1 голос
/ 21 января 2010

Я создал компонент 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)"/>

Полагаю, я хочу распространить события в компоненте на родительский компонент с переименованием события.

Ответы [ 4 ]

4 голосов
/ 22 января 2010

Вы можете сделать это с наименьшим количеством кода, создав класс для перенаправления событий. Вам нужен класс, который принимает диспетчер исходного события, имя исходного события, имя целевого события и диспетчер целевого события. Скажем, вы называете это 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;
        }
    }
}
0 голосов
/ 22 января 2010

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);
}
0 голосов
/ 22 января 2010

Вы можете сделать это через метаданные компонента:

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

Или вы можете просто вспомнить события и прослушать их в родительском компоненте, хотя я не рекомендую этого.

0 голосов
/ 22 января 2010

Это не должно быть слишком сложно.

Сначала вам нужно решить, нужно ли вашим событиям (listBoxChanged, comboBoxClick) сохранять данные вместе с ними. В таком случае создайте 2 пользовательских события (по одному на каждое) с переменной, в которой хранятся данные для передачи.

В MyComponent вам необходимо добавить прослушиватели к событиям щелчка ComboBox и событию изменения списка. В ваших обработчиках методов отправьте событие типа, который вы только что создали.

Не забудьте добавить 2 метатеги Event поверх вашего компонента, чтобы получить автозаполнение listBoxChanged & comboBoxClick

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...