I came across this strange behavior (I'm not sure if it qualifies to be called a bug, but it definitely is not a feature) in Flex while trying to add icons to the MenuBar
control.
The icons are displayed properly if both the MenuBar
and the icon-embed variables are declared in the main application class. But if they are nested inside another component, only the top level menu-items' icons are displayed - child menu items' icons are not displayed.
After some debugging I realized that only the top-level menu items are displayed using the itemToIcon
method of the MenuBar
class; child menu-items are displayed using the itemToIcon
method of the Menu
class. The problem here is that even though both of these methods use document[data[iconField]]
to grab the icon-embed class, the document
properties of these two objects point to different items. The document
property of the MenuBar
points correctly to the enclosing component (MyPanel
). Whereas, for some reason that I don't understand, the document
property for nested Menu
points to the MainApplication
class.
In short, while rendering icons of a MenuBar
within a component, flex searches the component class for icons of top-level menu items, and the main-application class for icons of its nested menu items. The obvious workaround is to embed all icons to public static const
in some class and to keep appropriate references to them in both application and component classes. But that doesn't sound so pretty to me (even though that's what I am doing now). Does anyone know better?
Here is example code and screenshots to demonstrate the issue:
<!--The main Application class-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="create()" xmlns:local="*">
<mx:Label text="MenuBar in the Application works fine"/>
<mx:MenuBar id="menuBar" top="10" left="10"
dataProvider="{menuBarCollection}" labelField="@label"
iconField="@icon" />
<local:MyPanel/>
<mx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
[Bindable]
protected var menuBarCollection:XMLListCollection;
[Embed(source="assets/icon_one.png")]
public var iconOne_App:Class;
[Embed(source="assets/icon_two.png")]
public var iconTwo_App:Class;
private function create():void
{
menuBarCollection = new XMLListCollection(XMLList(
'<menuitem label="One" icon="iconOne_App">' +
'<menuitem label="Two" icon="iconTwo_App"/>' +
'<menuitem label="Three" icon="iconTwo_App"/>' +
'</menuitem>'
));
}
]]>
</mx:Script>
</mx:Application>
<!--MyPanel.mxml-->
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" height="144"
creationComplete="create();" horizontalAlign="center" verticalAlign="middle">
<mx:Text text="MenuBar inside a component doesn't display icons properly"/>
<mx:MenuBar id="menuBar" top="10" left="10"
dataProvider="{menuBarCollection}" labelField="@label"
iconField="@icon" />
<mx:Script>
<![CDATA[
import mx.collections.XMLListCollection;
[Bindable]
protected var menuBarCollection:XMLListCollection;
[Embed(source="assets/icon_one.png")]
public var iconOne_Panel:Class;
[Embed(source="assets/icon_two.png")]
public var iconTwo_Panel:Class;
private function create():void
{
menuBarCollection = new XMLListCollection(XMLList(
//top level item referring to component
//this icon is displayed
'<menuitem label="ParentIcon_panel" icon="iconOne_Panel">' +
//nested item referring to component
//this icon is not displayed
'<menuitem label="ChildIcon_panel" icon="iconTwo_Panel"/>' +
//nested item referring to application
//this icon is displayed
'<menuitem label="ChildIcon-app" icon="iconTwo_App"/>' +
'</menuitem>' +
//top level item referring to Application
//this icon is not displayed
'<menuitem label="ParentIcon_app" icon="iconOne_App"/>'
));
}
]]>
</mx:Script>
</mx:Panel>