Меню, прикрепленное к mx.controls.PopUpButton, никогда не меняется - PullRequest
0 голосов
/ 01 января 2012

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

Пожалуйста, просто поместите 2 файла ниже в проект Flash Builder 4.6, и они сразу запустятся.

Моя проблемачто меню, прикрепленное к моему (слегка измененному) пользовательскому PopUpButton, никогда не меняется, даже если базовый поставщик данных Array изменяется при нажатии одной из 3 кнопок справа от него:

screenshot

AuxButtonTest.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:comps="*"
    creationComplete="init()">

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

            private const XML1:XML = 
                <pref>
                    <aux event="1">One</aux>
                    <aux event="2">Two</aux>
                    <aux event="3">Three</aux>
                    <aux event="4">Four</aux>
                    <aux event="5">Five</aux>
                </pref>;

            private const XML2:XML = 
                <pref>
                    <aux event="1">One</aux>
                    <aux event="2">Two</aux>
                </pref>;

            private const XML3:XML = 
                <pref>
                    <aux event="3">Three</aux>
                </pref>;

            public function init():void {
                _auxBtn.update(XML1.aux);
            }

            //private function handleAuxChosen(event:PrefEvent):void {
                //Alert.show(event.toString());
            //}
        ]]>
    </fx:Script>

    <s:controlBarContent>
            <!-- commented: aux_chosen="handleAuxChosen(event)" -->
        <comps:AuxButton id="_auxBtn" />
        <s:Button id="_btn1" label="XML 1" click="_auxBtn.update(XML1.aux);" />
        <s:Button id="_btn2" label="XML 2" click="_auxBtn.update(XML2.aux);" />
        <s:Button id="_btn3" label="XML 3" click="_auxBtn.update(XML3.aux);" />
    </s:controlBarContent>
</s:Application>

AuxButton.mxml (мой пользовательский компонент, основанный на PopUpButton):

<?xml version="1.0" encoding="utf-8"?>
<mx:PopUpButton
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    popUp="{_menu}"
    creationComplete="init(event)">

    <fx:Metadata> 
        <!-- [Event(name="aux_chosen", type="PrefEvent")] -->
    </fx:Metadata>

    <fx:Script>
        <![CDATA[
            import mx.controls.Menu;
            import mx.events.MenuEvent;
            import mx.events.FlexEvent;

            private var _str:String;

            [Bindable]
            private var _data:Array = new Array();

            [Bindable]
            private var _menu:Menu = new Menu();

            private function init(event:FlexEvent):void {
                _menu.dataProvider = _data;
                _menu.addEventListener('itemClick', handleMenu);
                addEventListener('click', handleClick);
            }

            public function update(xlist:XMLList):void {
                _data.length = 0;
                for each (var xml:XML in xlist) {
                    _data.push({label: xml, event: xml.@event});
                }

                label = _data[0].label;
                _str = _data[0].event;

                enabled = true;
            }

            private function handleMenu(event:MenuEvent):void {
                label = event.label;
                _str = event.item.event;
            }           

            private function handleClick(event:MouseEvent):void {
                enabled = false;
                //dispatchEvent(new PrefEvent(PrefEvent.AUX_CHOSEN, _str));
            }
        ]]>
    </fx:Script>

</mx:PopUpButton>

Я прокомментировал свое пользовательское событие - здесь это не имеет значения.

Пожалуйста, просто нажмите несколько раз на кнопки и посмотрите на меню - оно всегда содержит 5 пунктов, и это неправильно.

ОБНОВЛЕНИЕ: Спасибо за ответы - следующий код теперь работает для меня.Мне все еще интересно, почему ArrayList не поддерживается, но ArrayCollection работает отлично.

enter image description here

AuxButtonText.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:PopUpButton
    xmlns:fx="http://ns.adobe.com/mxml/2009" 
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    popUp="{_menu}"
    creationComplete="init(event)">

    <fx:Script>
        <![CDATA[
            import mx.controls.*;
            import mx.events.*;
            import mx.collections.*;

            private var _str:String;

            [Bindable]
            private var _data:ArrayCollection = new ArrayCollection();
            //private var _data:ArrayList = new ArrayList();

            [Bindable]
            private var _menu:Menu = new Menu();

            private function init(event:FlexEvent):void {
                _menu.dataProvider = _data;
                _menu.addEventListener('itemClick', handleMenu);
                addEventListener('click', handleClick);
            }

            public function update(xlist:XMLList):void {
                _data.removeAll();

                if (xlist == null || xlist.length() == 0) {
                    enabled = false;
                    return;
                }

                for each (var xml:XML in xlist)
                    _data.addItem({label: xml, event: xml.@event});

                label = _data.getItemAt(0).label;
                _str = _data.getItemAt(0).event;

                enabled = true;
            }

            private function handleMenu(event:MenuEvent):void {
                label = event.label;
                _str = event.item.event;
            }           

            private function handleClick(event:MouseEvent):void {
                enabled = false;
                //dispatchEvent(new PrefEvent(PrefEvent.AUX_CHOSEN, _str));
            }
        ]]>
    </fx:Script>

</mx:PopUpButton>

AuxButton.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:comps="*"
    initialize="init()">

    <fx:Script>
        <![CDATA[
            private const XML1:XML = 
                <pref>
                    <aux event="1">One</aux>
                    <aux event="2">Two</aux>
                    <aux event="3">Three</aux>
                    <aux event="4">Four</aux>
                    <aux event="5">Five</aux>
                </pref>;

            private const XML2:XML = 
                <pref>
                    <aux event="1">One</aux>
                    <aux event="2">Two</aux>
                </pref>;

            private const XML3:XML = 
                <pref>
                    <aux event="3">Three</aux>
                </pref>;

            private const XML4:XML = 
                <pref>
                </pref>;

            public function init():void {
                _auxBtn.update(XML1.aux);
            }
        ]]>
    </fx:Script>

    <s:controlBarContent>
        <comps:AuxButton id="_auxBtn" />
        <s:Button id="_btn1" label="XML 1" click="_auxBtn.update(XML1.aux);" />
        <s:Button id="_btn2" label="XML 2" click="_auxBtn.update(XML2.aux);" />
        <s:Button id="_btn3" label="XML 3" click="_auxBtn.update(XML3.aux);" />
        <s:Button id="_btn4" label="LEN=0" click="_auxBtn.update(XML4.aux);" />
        <s:Button id="_btn5" label="NULL" click="_auxBtn.update(null);" />
    </s:controlBarContent>
</s:Application>

Ответы [ 2 ]

2 голосов
/ 02 января 2012

Массивы не отправляют никаких событий, когда их содержимое изменяется. Как правило: использование [Bindable] в массиве и использование его в качестве некоторого типа dataProvider является обычно плохой идеей, поскольку добавление / удаление не отправляет никаких событий и поэтому не будет обрабатываться любой компонент.

Вместо Array используйте ArrayCollection, который отправляет события типа CollectionEvent.COLLECTION_CHANGE при изменении его содержимого. Большинство компонентов в Flex SDK обрабатывают эти события и обновляются соответствующим образом. Итак, следующий код работает, так как присвоение нового source для ArrayCollection отправляет CollectionEvent, что заставляет Menu обновить свои пункты меню.

// you don't need [Bindable] on _data
private var _data:ArrayCollection = new ArrayCollection();

public function update(xlist:XMLList):void
{
    var items:Array = [];

    for each (var xml:XML in xlist)
    {
        items.push({label: xml, event: xml.@event});
    }

    _data.source = items;

    if (items.length > 0)
    {
        label = items[0].label;
        _str = items[0].event;
    }

    enabled = true;
}
1 голос
/ 01 января 2012

Моя проблема заключается в том, что меню, прикрепленное к моему (слегка измененному) пользовательскому PopUpButton, никогда не меняется - даже если базовый поставщик данных Array изменился

В этом заключается ваша проблема.У вас нет кода, чтобы изменить dataProvider меню или синхронизировать его с вашей личной переменной _data.Массив _data действительно изменяется, но вы не закодировали никаких отношений между _data и _menu.dataProvider.

Начальное значение задается в вашем методе init:

        private function init(event:FlexEvent):void {
            _menu.dataProvider = _data;
            _menu.addEventListener('itemClick', handleMenu);
            addEventListener('click', handleClick);
        }

Но этоникогда не менялся при изменении данных.

Я сделаю одну небольшую заметку, чтобы добавить, что ваш метод init () вызывается для creationComplete.Это означает, что компонент проходит полный жизненный цикл один раз;затем вы изменяете dataProvider в _menu, заставляя его снова пройти жизненный цикл, чтобы перерисовать с новым dataProvider.Это обычно нежелательно.Вы должны прочитать о жизненном цикле компонентов Flex , чтобы понять, какие события запускаются и когда.Возможно, я бы порекомендовал установить dataProvider при инициализации, которая вызывается после запуска createChildren (), но до того, как дочерние элементы будут измерены и измерены.

В любом случае, быстрое решение состоит в том, чтобы просто изменить _menu.dataProvider наМуха в вашем обновлении:

        public function update(xlist:XMLList):void {
            _data.length = 0;
            for each (var xml:XML in xlist) {
                _data.push({label: xml, event: xml.@event});
            }

            label = _data[0].label;
            _str = _data[0].event;

            enabled = true;
                        // new code
                        _menu.dataProvider = _data;
        }
...