2012-01-01 2 views
0

Я подготовил очень простой тестовый пример для демонстрации моей проблемы.Меню, прикрепленное к mx.controls.PopUpButton никогда не изменяется

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

Моя проблема заключается в том, что меню прилагается к моей (слегка измененный) обычай PopUpButton никогда не меняется - даже если основной поставщик массива данных изменяется при нажатии одной из 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 (мой заказ со mponent на основе 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: [email protected]}); 
       } 

       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: [email protected]}); 

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

+! для вопроса с четко определенной проблемой и достаточно кода, чтобы помочь нам решить проблему. – JeffryHouser

+0

Ugh; слишком поздно удалить мой +1. Код, который вы указали, не создает скриншот, который вы опубликовали. – JeffryHouser

+0

Извините, теперь это так. –

ответ

2

Массивы не отправлять какие-либо события, когда меняется их содержание. Как правило: использование [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: [email protected]}); 
    } 

    _data.source = items; 

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

    enabled = true; 
} 
+1

В теории вашего ответа есть много неправильного. Во-первых, даже если вы используете ArrayCollection, добавление или удаление элементов в эту коллекцию не приведет к привязке. Он сгорит событие collectionChange. Классы на основе MX имеют встроенный код для ответа на событие collectionChange и соответственно обновляют список отображения. Я верю в Spark, этот код находится в DataGroup. Этот подход отличается от того, как работает привязка. Во-вторых, ваш код «_data.source = items» не инициирует связывание событий, потому что _data фактически не изменен; только свойство на – JeffryHouser

+0

.. объект, на который указывает. В-третьих, вы говорите, что, как правило, плохая идея использовать Bindable для массива. Как так? Я подозреваю, что ваш код действительно решает проблему; но не из-за привязки, потому что связанные с списком классы отвечают на событие collectionChange, которое запускается при изменении свойства источника. – JeffryHouser

+0

Спасибо, Герхард - ArrayCollection хорошо работает для меня! (Первоначально я сам пытался использовать ArrayList, но по какой-то причине он не отображается корректно mx.controls.Menu - см. Мой обновленный вопрос). Кроме того, элементы: массив в вашем предложении не доступен - я использую ArrayCollection, и он тоже работает. –

1

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

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

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

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

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

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

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

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

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

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

Это похоже на обходное решение для меня - установка _menu.dataProvider снова и снова (когда данные XML поступают с моего сервера-демона). Почему _menu не обнаруживает, что содержимое _data изменилось? –

+0

@AlexanderFarber Я задаю вам вопрос: «Почему _menu обнаружит, что содержимое _data изменилось?» Я в замешательстве, почему вы думаете, что эти два должны быть связаны, когда вы не написали код, чтобы действительно их связать. Ответ о том, почему изменение одного не меняется, включает в себя сведения о том, как переменные указывают на пятна в памяти; и, вероятно, мне понадобится пару часов, чтобы написать. – JeffryHouser

+0

Отличное предложение об инициализации = "....", спасибо –

Смежные вопросы