附加到 mx.controls.PopUpButton 的菜单永远不会改变 [英] Menu attached to mx.controls.PopUpButton never changes
问题描述
我准备了一个非常简单的测试用例来演示我的问题.
I have prepared a very simple test case to demo my problem.
请将以下 2 个文件放入 Flash Builder 4.6 项目中,它们将立即运行.
Please just place the 2 files below into a Flash Builder 4.6 project and they will run instantly.
我的问题是附加到我的(稍作修改的)自定义 PopUpButton 的菜单永远不会改变 - 即使当您单击它右侧的 3 个按钮之一时底层 Array 数据提供程序发生了更改:
My problem is that the menu attached to my (slightly modified) custom PopUpButton never changes - even though the underlying Array data provider is changed when you click one of the 3 buttons on the right side of it:
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 的自定义组件):
AuxButton.mxml (my custom component based on 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>
我已经注释掉了我的自定义事件 - 这里无关紧要.
I've commented my custom event out - it doesn't matter here.
请点击按钮几次,然后查看菜单 - 它总是有 5 个项目,这是错误的.
Please just click at the buttons few times and then look at the menu - it always has 5 items and that is wrong.
更新:感谢您的回答 - 以下代码现在对我有用.我仍然想知道为什么不支持 ArrayList,但 ArrayCollection 工作正常.
UPDATE: Thank you for the answers - the following code works now for me. I still wonder why isn't ArrayList supported, but ArrayCollection works fine.
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>
推荐答案
当数组的内容发生变化时,它不会调度任何事件.根据经验:在数组上使用 [Bindable]
并将其用作某种 dataProvider通常 是一个坏主意,因为添加/删除不会调度任何事件因此不会被任何组件处理.
Arrays do not dispatch any events when their content changes. As a rule of thumb: Using [Bindable]
on an Array and using it as some kind of dataProvider is usually a bad idea since adding/removing doesn't dispatch any events and therefore won't be handled by any component.
代替 Array
使用 ArrayCollection
,它会在其内容发生变化时分派 CollectionEvent.COLLECTION_CHANGE
类型的事件.Flex SDK 中的大多数组件都会处理这些事件并相应地更新自身.因此,以下代码有效,因为将新的 source
分配给 ArrayCollection
分派了一个 CollectionEvent
这会导致 Menu
更新其菜单项.
Instead of Array
use an ArrayCollection
which dispatches events of type CollectionEvent.COLLECTION_CHANGE
whenever its content changes. Most components in the Flex SDK handle those events and update itself accordingly. So, the following code works since assigning a new source
to the ArrayCollection
dispatches a CollectionEvent
which causes the Menu
to update its menu items.
// 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;
}
这篇关于附加到 mx.controls.PopUpButton 的菜单永远不会改变的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!