Enhanced States Syntax - Functional and Design SpecificationEnhanced States Syntax - Functional and Design Specification | Glossary | Summary and Background | Usage Scenario | Detailed Description | API Description | B Features | Additional Implementation Details | Prototype Work | Compiler Work | Web Tier Compiler Impact | Flex Feature Dependencies | Backwards Compatibility | Accessibility | Performance | Globalization | Localization | Issues and Recommendations | Documentation | QA
Glossarystate - A state (or 'view-state') is a collection of changes (called overrides) to a view. The changes within a state can comprise additions or removals of components as well as changes to their properties, styles, and behavior.
Summary and BackgroundGoals
Usage ScenarioFlex 4 will target all of the legacy usage scenarios of classic Flex states functionality (stateful components, states as application "views" or "pages", effects and transitions between view states, etc.). This document outlines what is primarily a syntax change for the existing functionality. Detailed DescriptionInline States SyntaxStates will be promoted to a full language feature of MXML during the Flex 4 time frame. A more terse and flexible inline syntax will be provided for expressing all state-specific changes to a component instance. The classic syntax will be deprecated as of MXML version 4.0. First, a brief description of how the states model will change for version 4.0 components:
API DescriptionA detailed overview of the new inline syntax follows: State-Specific Component InstancesThe AddChild and RemoveChild override mechanism will be replaced by a new includeIn language attribute that can be used to decorate inline MXML component instance tags with the set of states for which the specific instance is to be realized. The new includeIn attribute accepts a comma delimited list of state names, all of which must have been previously declared within the document's states array. Optionally, excludeFrom can be used to define an explicit "black-list" of states where the instance will not apply. The excludeFrom and includeIn attributes are mutually exclusive. If both are defined on a single tag, it is considered an error and an appropriate compiler error will be issued. An example: <!-- Given the states A,B,C -->
<m:states>
<m:State name="A"/>
<m:State name="B"/>
<m:State name="C"/>
</m:states>
<!-- This button will appear in only states A and B -->
<Button label="Click Me" includeIn="A, B"/>
<!-- This button will appear in states A and B -->
<Button label="Button C" excludeFrom="C"/>
The includeIn and excludeFrom attributes will be treated as reserved language keywords by the MXML compiler. The includeIn and excludeFrom attributes can be legally specified on any MXML object within a document, with the exception of:
In addition to referencing mutually exclusive states, both attributes also support composite states (currently known as overlays). A more detailed specification of how Overlays are supported in the new state model will be incorporated into the Overlays specification (not yet drafted).
BEFORE - Classic states syntax (O'Reilly Programming Flex 2): <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:states> <mx:State name="newCheckbox"> <mx:AddChild relativeTo="{vbox}"> <mx:CheckBox id="checkbox" label="Checkbox" /> </mx:AddChild> </mx:State> <mx:State name="newTextArea" basedOn="newCheckBox"> <mx:AddChild relativeTo="{vbox}"> <mx:TextArea id="textarea" /> </mx:AddChild> </mx:State> </mx:states> <mx:VBox id="vbox"> <mx:Button label="Click" click="currentState='newCheckbox'" /> <mx:Button label="Click" click="currentState='newTextArea'" /> </mx:VBox> </mx:Application> AFTER - Inline states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"> <m:states> <m:State name="default"/> <m:State name="newCheckbox"/> <m:State name="newTextArea"/> </m:states> <mx:VBox> <mx:Button label="Click" click="currentState='newCheckbox'" /> <mx:Button label="Click" click="currentState='newTextArea'" /> <mx:CheckBox id="checkbox" label="Checkbox" includeIn="newCheckbox, newTextArea"/> <mx:TextArea id="textarea" includeIn="newTextArea"/> </mx:VBox> </mx:Application> Transient component instances (instances that appear across one or more states), are declared inline with the rest of the document, essentially at their "natural" location in the DOM. The context of a state-specific instance is no longer explicitly defined by the relativeTo/position properties of AddChild. Location is instead inferred by the inline placement. Note that for a state-specific node to be realized within a state, its ancestors must also be defined within the same state as well. For example, a child is not visible in StateA if its parent is excluded from StateA. If such a scenario is detected, a compiler warning will be issued. BEFORE - Classic states syntax (O'Reilly Programming Flex 2): <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:states> <mx:State name="newTextInput"> <mx:AddChild relativeTo="{checkbox1}" position="after"> <mx:TextInput id="textinput" /> </mx:AddChild> </mx:State> </mx:states> <mx:VBox id="vbox"> <mx:CheckBox id="checkbox1" label="One" /> <mx:CheckBox id="checkbox2" label="Two" /> <mx:Button id="button" label="Click" click="currentState='newTextInput'" /> </mx:VBox> </mx:Application> AFTER - Inline states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"> <m:states> <m:State name="default"/> <m:State name="newTextInput"/> </m:states> <mx:VBox> <mx:CheckBox label="One" /> <mx:TextInput includeIn="newTextInput"/> <mx:CheckBox label="Two" /> <mx:Button id="button" label="Click" click="currentState='newTextInput'" /> </mx:VBox> </mx:Application> And another example, demonstrating how the use of RemoveChild in the legacy syntax, translates to the new:
BEFORE - Classic states syntax (O'Reilly Programming Flex 2): <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:states> <mx:State name="noCheckboxes"> <mx:RemoveChild target="{checkbox1}" /> <mx:RemoveChild target="{checkbox2}" /> </mx:State> </mx:states> <mx:VBox id="vbox"> <mx:CheckBox id="checkbox1" label="One" /> <mx:CheckBox id="checkbox2" label="Two" /> <mx:Button id="button" label="Click" click="currentState='noCheckboxes'" /> </mx:VBox> </mx:Application> AFTER - Inline states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"> <m:states> <m:State name="default"/> <m:State name="noCheckboxes"/> </m:states> <mx:VBox id="vbox"> <mx:CheckBox label="One" excludeFrom="noCheckboxes"/> <mx:CheckBox label="Two" includeIn="default"/> <!-- Works as above --> <mx:Button id="button" label="Click" click="currentState='noCheckboxes'" /> </mx:VBox> </mx:Application> ReparentingWhere one would generally have used a RemoveChild followed by an AddChild to reparent instances within a state (Flex 3), a new Reparent language tag will be provided that can be used as an inline insertion point for a given component instance. The Reparent tag itself provides a target attribute which specifies the component instance to reparent. The includeIn attribute used in combination with the Reparent tag specifies the context for which the reparenting is to take place. There is no formal runtime representation of the Reparent tag itself. The compiler will convert the Reparent into explicit remove and insertion overrides for the given state(s). Note that for a Reparent tag to be valid, it must refer to a document node that is not already realized within the state that the reparenting is to take place. Additionally, two or more Reparent tags must not target the same DOM node within the same state. The set of reparent operations in a given state must, when combined, result in a valid DOM (no circular references, etc.). If any of these error conditions are detected, a compiler error will be issued. Additional restrictions on the Reparent tag are as follows:
See the Media Chat example later for an example Reparent use case. State-Specific Property ValuesThe SetProperty, SetStyle, and SetEventHandler overrides will be replaced by an inline attribute notation. State-specific property values can be expressed by utilizing the 'dot' operator on any writable XML attribute to essentially provide a hint to the compiler that the attribute is to be 'scoped' to a specific state. <!-- Button's label in base state is "XXX', in state A, "YYY", and in state B, "ZZZ" --> <Button label="XXX" label.A="YYY" label.B="ZZZ" /> The unqualified property/value pair (e.g property=value) is assumed to be the default base value and the value within all states, unless specifically overridden. <!-- Default value, 'YYY' applies to all named states, except the 'A' state --> <Button label="YYY" label.A="XXX" /> The "drill-down" (dot) syntax can be utilized with most component properties, styles, or event handlers. The state-specific attribute syntax cannot however be used with built-in language attributes. The full set of language attributes are detailed in the Flex 4 MXML 2009 language specification, but they include (for example), id, states, frameRate, etc. To facilitate the ability to "clear" a property value within a given state, a new directive '@Clear" will be introduced. This essentially results in property being unset. e.g. For a style property, it would result in a clearStyle() being invoked (thus allowing the natural cascade to take effect). The @Clear value directive can be used with properties, styles, and event handlers. <!-- In state A, the color style is cleared. Any CSS selectors can now take effect. --> <Button color="0xFF0000" color.A="@Clear" /> Some additional examples of state-specific property syntax:
BEFORE - Classic states syntax (O'Reilly Programming Flex 2): <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:states> <mx:State name="landState"> <mx:SetStyle target="{car}" name="color" value="0xFF0000" /> <mx:SetStyle target="{train}" name="color" value="0xFF0000" /> <mx:SetStyle target="{motorcycle}" name="color" value="0xFF0000" /> </mx:State> <mx:State name="airState"> <mx:SetStyle target="{helicopter}" name="color" value="0xFF0000" /> <mx:SetStyle target="{airplane}" name="color" value="0xFF0000" /> </mx:State> <mx:State name="waterState"> <mx:SetStyle target="{boat}" name="color" value="0xFF0000" /> <mx:SetStyle target="{submarine}" name="color" value="0xFF0000" /> </mx:State> </mx:states> <mx:VBox id="vbox"> <mx:HBox> <mx:Button id="land" label="Land" click="currentState='landState'" /> <mx:Button id="air" label="Air" click="currentState='airState'" /> <mx:Button id="water" label="Water" click="currentState='waterState'" /> </mx:HBox> <mx:CheckBox id="helicopter" label="Helicopter" /> <mx:CheckBox id="motorcycle" label="Motorcycle" /> <mx:CheckBox id="car" label="Car" /> <mx:CheckBox id="airplane" label="Airplane" /> <mx:CheckBox id="train" label="Train" /> <mx:CheckBox id="boat" label="Boat" /> <mx:CheckBox id="submarine" label="Submarine" /> </mx:VBox> </mx:Application> AFTER - Inline states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"> <m:states> <m:State name="landState"/> <m:State name="airState"/> <m:State name="waterState"/> </m:states> <mx:VBox id="vbox"> <mx:HBox> <mx:Button id="land" label="Land" click="currentState='landState'" /> <mx:Button id="air" label="Air" click="currentState='airState'" /> <mx:Button id="water" label="Water" click="currentState='waterState'" /> </mx:HBox> <mx:CheckBox label="Helicopter" color.airState="0xFF0000"/> <mx:CheckBox label="Motorcycle" color.landState="0xFF0000" /> <mx:CheckBox label="Car" color.landState="0xFF0000" /> <mx:CheckBox label="Airplane" color.airState="0xFF0000"/> <mx:CheckBox label="Train" color.landState="0xFF0000" /> <mx:CheckBox label="Boat" color.waterState="0xFF0000"/> <mx:CheckBox label="Submarine" color.waterState="0xFF0000"/> </mx:VBox> </mx:Application>
BEFORE - Classic states syntax (O'Reilly Programming Flex 2): <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:states> <mx:State name="enabled"> <mx:SetProperty target="{textinput}" name="enabled" value="{true}" /> <mx:SetEventHandler target="{button}" name="click" handler="currentState=''" /> <mx:SetProperty target="{button}" name="label" value="Disable" /> </mx:State> </mx:states> <mx:HBox id="hbox"> <mx:Button id="button" label="Enable" click="currentState='enabled'" /> <mx:TextInput id="textinput" enabled="false" text="example text" /> </mx:HBox> </mx:Application> AFTER - Inline states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"> <m:states> <m:State name="disabledState"/> <m:State name="enabledState"/> </m:states> <mx:HBox> <mx:Button id="button" label="Enable" label.enabledState="Disable" click="currentState='enabled'" click.enabledState="currentState=''" /> <mx:TextInput enabled="false" enabled.enabledState="true" text="example text" /> </mx:HBox> </mx:Application> The state-specific property value syntax can also be used with object based properties...
BEFORE - Classic states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:states> <mx:State name="glow"> <mx:SetProperty target="{b}" name="filters"> <mx:value> <mx:Array> <mx:GlowFilter /> </mx:Array> </mx:value> </mx:SetProperty> </mx:State> </mx:states> <mx:Button label="Button" id="b" click="currentState=currentState=='glow'?'':'glow'"> <mx:filters> <mx:DropShadowFilter distance="9" /> </mx:filters> </mx:Button> </mx:Application> AFTER - Inline states syntax: <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009"> <m:states> <m:State name="default"/> <m:State name="glow"/> </m:states> <mx:Button label="Button" click="currentState=currentState=='glow'?'':'glow'"> <mx:filters> <mx:DropShadowFilter distance="9" /> </mx:filters> <mx:filters.glow> <mx:GlowFilter/> </mx:filters.glow> </mx:Button> </mx:Application> <!-- Alternatively the above code could be written using state specific nodes --> <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:m="http://ns.adobe.com/mxml/2009" xmlns:mx="library:ns.adobe.com/flex/halo"> <m:states> <m:State name="default"/> <m:State name="glow"/> </m:states> <mx:Button label="Button" click="currentState=currentState=='glow'?'':'glow'"> <mx:filters> <mx:DropShadowFilter distance="9" includeIn="default" /> <mx:GlowFilter includeIn="glow"/> </mx:filters> </mx:Button> </mx:Application> When state-specific attributes are used with composite states (Overlays), along with mutually exclusive states, the order of precedence is as follows:
State GroupsIf several states within a stateful document are quite similar, and are commonly used together when setting state-specific properties, a "state group" can be created. State groups are essentially state macros that can be used directly within an includeIn or excludeFrom, or a state-specific property's scope. For example, given this case: <m:states> <m:State name="A"/> <m:State name="B"/> <m:State name="C"/> <m:State name="D"/> </m:states> ... <mx:Button label.A="SomeLabel" label.C="SomeLabel" label.D="SomeLabel"/> <mx:Button includeIn="A,C,D"/> <mx:Button label.A="SomeLabel" label.B="SomeLabel"/> <mx:Button includeIn="A,B"/> If one discoveres a pattern of treating a set of states identically in some cases, a state group representing these states can be created and referred to as appropriate. <m:states> <m:State name="A" stateGroups="G1,G2"/> <m:State name="B" stateGroups="G2"/> <m:State name="C" stateGroups="G1"/> <m:State name="D" stateGroups="G1"/> </m:states> ... <mx:Button label.G1="SomeLabel"/> <mx:Button includeIn="G1"/> <mx:Button label.G2="SomeLabel"/> <mx:Button includeIn="G2"/> The stateGroups attribute accepts a comma delimited list of valid state identifiers (whitespace ignored). Custom Creation and Destruction PoliciesitemCreationPolicy Historically if one wanted a custom creation policy (immediate vs. deferred instantiated) for a state-specific component instance they would utilize the creationPolicy attribute of the AddChild override. To provide for a similar level of control, a per-item based creation policy language attribute (itemCreationPolicy) will be introduced. Supported values for itemCreationPolicy are ItemCreationPolicy.DEFERRED, ItemCreationPolicy.IMMEDIATE. The itemCreationPolicy language attribute can be specified on any MXML object supporting the includeIn and excludeFrom attributes. An item creation policy of ItemCreationPolicy.DEFERRED is the default, the instance is created when needed. An item creation policy of ItemCreationPolicy.IMMEDIATE means that the object will be created as soon as the owning document context is initialized.
BEFORE - Classic states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"> <mx:states> <mx:State name="newTextInput"> <mx:AddChild relativeTo="{checkbox1}" position="after" creationPolicy="all"> <mx:TextInput id="textinput" /> </mx:AddChild> </mx:State> </mx:states> <mx:VBox id="vbox"> <mx:CheckBox id="checkbox1" label="One" /> <mx:CheckBox id="checkbox2" label="Two" /> <mx:Button id="button" label="Click" click="currentState='newTextInput'" /> </mx:VBox> </mx:Application> AFTER - Inline states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"> <mx:states> <mx:State name="default"/> <mx:State name="newTextInput"/> </mx:states> <mx:VBox id="vbox"> <mx:CheckBox label="One" /> <mx:TextInput includeIn="newTextInput" itemCreationPolicy="immediate"/> <mx:CheckBox label="Two" /> <mx:Button id="button" label="Click" click="currentState='newTextInput'" /> </mx:VBox> </mx:Application> itemDestructionPolicy By default, after the framework initially creates a state-specific instance, the instance is cached indefinitely, even after switching to a state where the item is excluded. An optional itemDestructionPolicy language attribute is provided as a means of ensuring a state-specific instance is destroyed upon leaving a state in which it exists. Typically it is more efficient to allow items to be cached, however there are times, such as for rarely visited states, that you may wish not to take the memory hit for a cached instance. Supported values for itemDestructionPolicy are "never" and "auto". The itemDestructionPolicy language attribute can be specified on any MXML object supporting the includeIn and excludeFrom attributes. An item destruction policy of "never" is the default, all state-specific instances are realized when appropriate and cached indefinitely. An item destruction policy of "auto" means that the object will be removed from the DOM and all document and framework references to the object cleared, upon leaving a state where the instance exists. In the example below, the text input instance will be released upon switching to then from, the 'newTextInput' state:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" layout="absolute"> <mx:states> <mx:State name="default"/> <mx:State name="newTextInput"/> </mx:states> <mx:VBox id="vbox"> <mx:CheckBox label="One" /> <mx:TextInput includeIn="newTextInput" itemDestructionPolicy="auto"/> <mx:CheckBox label="Two" /> <mx:Button id="button" label="Click" click="currentState='newTextInput'" /> </mx:VBox> </mx:Application> Some Additional ExamplesHere is an example that ties everything together. A real world use case (Flex Media Chat, www.flashcomguru.com)...
BEFORE - Classic states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:states> <mx:State name="chatState"> <mx:SetProperty target="{mainPanel}" name="width" value="80%"/> <mx:SetProperty target="{mainPanel}" name="height" value="80%"/> <mx:RemoveChild target="{submit}"/> <mx:RemoveChild target="{female}"/> <mx:RemoveChild target="{hbox1}"/> <mx:RemoveChild target="{hbox2}"/> <mx:RemoveChild target="{username}"/> <mx:AddChild relativeTo="{mainPanel}" position="lastChild"> <mx:VBox width="100%" height="100%" verticalGap="8" verticalAlign="middle" horizontalAlign="left" id="vbox2"> <mx:HDividedBox width="100%" height="100%" liveDragging="true"> <Chat:ChatTextarea id="hist" editable="false" width="75%" height="100%" paddingLeft="3" focusAlpha="0" htmlText="{chat.chatHistory}"> </Chat:ChatTextarea> <mx:List id="userlist" height="100%" width="25%" itemRenderer="usersRenderer" dataProvider="{chat.dpUsers}"></mx:List> </mx:HDividedBox> <mx:HBox width="100%" verticalAlign="middle" horizontalAlign="center" id="hbox6"> <mx:HBox width="75%" verticalAlign="middle" horizontalAlign="center" id="hbox5"> <mx:ColorPicker id="picker" toolTip="Font color"/> <mx:TextInput width="100%" id="msg" paddingLeft="3" focusAlpha="0" keyUp="checkSend(event)" color="{picker.selectedColor}" /> <mx:Button label="Send" id="send" click="sendMsg()"/> </mx:HBox> <mx:HBox width="25%" verticalAlign="middle" horizontalAlign="center" id="hbox7"> </mx:HBox> </mx:HBox> </mx:VBox> </mx:AddChild> <mx:SetProperty target="{text1}" name="text" value="FlexMediaChat"/> <mx:RemoveChild target="{vbox1}"/> <mx:SetProperty target="{hbox4}" name="width" value="75%"/> <mx:SetStyle target="{mainPanel}" name="horizontalAlign" value="left"/> <mx:SetStyle target="{text1}" name="color"/> <mx:RemoveChild target="{image1}"/> <mx:AddChild relativeTo="{hbox8}" position="lastChild" target="{image1}"/> <mx:RemoveChild target="{text1}"/> <mx:AddChild relativeTo="{hbox8}" position="lastChild" target="{text1}"/> <mx:RemoveChild target="{hbox4}"/> <mx:AddChild relativeTo="{hbox9}" position="lastChild" target="{hbox4}"/> <mx:SetProperty target="{hbox9}" name="width" value="100%"/> <mx:AddChild relativeTo="{hbox4}" position="lastChild"> <mx:Spacer width="80%" height="100%"/> </mx:AddChild> </mx:State> </mx:states> <mx:Panel width="410" height="210" layout="vertical" id="mainPanel" horizontalAlign="center" headerHeight="10" verticalAlign="middle" fontSize="12" paddingTop="10" paddingLeft="10" paddingRight="10"paddingBottom="10" verticalScrollPolicy="off" horizontalScrollPolicy="off"> <mx:HBox width="97%" id="hbox9"> <mx:HBox width="97%" id="hbox4" horizontalAlign="left"> <mx:Image source="assets/internet-group-chat.png" id="image1"/> <mx:Text text="User Login" fontWeight="bold" fontSize="18" id="text1" selectable="false" color="#333333"/> </mx:HBox> <mx:HBox id="hbox8" horizontalAlign="right"> </mx:HBox> </mx:HBox> <mx:VBox height="92%" width="95%" horizontalScrollPolicy="off" id="vbox1"> <mx:Spacer width="100%" height="6"/> <mx:HBox width="100%" id="hbox1"> <mx:Text text="Username:"/> <mx:TextInput id="username" width="269" focusAlpha="0" enter="connect(event)"/> </mx:HBox> <mx:HBox width="100%" id="hbox2"> <mx:RadioButtonGroup id="gender"/> <mx:Text text="Gender:"/> <mx:Spacer width="16" height="100%"/> <mx:Image id="maleicon" source="assets/male_login.png"/> <mx:RadioButton label="male" groupName="gender" selected="true" id="male"/> <mx:Image id="femaleicon" source="assets/female_login.png"/> <mx:RadioButton label="female" groupName="gender" id="female" selected="false"/> </mx:HBox> <mx:Spacer width="100%" height="7"/> <mx:HBox width="100%" id="hbox3" horizontalAlign="right"> <mx:Image source="assets/dialog-warning.png" id="warning"/> <mx:Text color="#e60000" id="status" text="Text"/> <mx:Spacer width="100%"/> <mx:Button label="Connect" click="connect( event )" id="submit" width="110" height="34" icon="@Embed('assets/go-next.png')"/> </mx:HBox> </mx:VBox> </mx:Panel> </mx:Application> AFTER - Inline states syntax: <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" m:version="4"> <m:states> <m:State name="defaultState"/> <m:State name="chatState"/> </m:states> <mx:Panel width="410" width.chatState="80%" height="110" height.chatState="80%" layout="vertical" id="mainPanel" horizontalAlign="center" horizontalAlign.chatState="left" headerHeight="10" verticalAlign="middle" fontSize="12" paddingTop="10" paddingLeft="10" paddingRight="10" paddingBottom="10" verticalScrollPolicy="off" horizontalScrollPolicy="off"> <mx:HBox width="97%" width.chatState="100%"> <mx:HBox width="97%" width.chatState="80%" id="hbox4" horizontalAlign="left"> <mx:Image source="assets/internet-group-chat.png" id="image1"/> <mx:Text text="User Login" text.chatState="FlexMediaChat" fontWeight="bold" fontSize="18" id="text1" selectable="false" color="#333333" color.chatState=""/> <mx:Spacer width="80%" height="100%" includeIn="chatState"/> </mx:HBox> <mx:HBox horizontalAlign="right"> <mx:Reparent target="{image1}" includeIn="chatState"/> <mx:Reparent target="{text1}" includeIn="chatState"/> </mx:HBox> <mx:Reparent target="{hbox4}" includeIn="chatState"/> </mx:HBox> <mx:VBox height="92%" width="95%" horizontalScrollPolicy="off" includeIn="defaultState"> <mx:Spacer width="100%" height="6"/> <mx:HBox width="100%" includeIn="defaultState"> <mx:Text text="Username:"/> <mx:TextInput id="username" width="269" focusAlpha="0" enter="connect(event)" includeIn="defaultState"/> </mx:HBox> <mx:HBox width="100%" includeIn="defaultState"> <mx:RadioButtonGroup/> <mx:Text text="Gender:"/> <mx:Spacer width="16" height="100%"/> <mx:Image id="maleicon" source="assets/male_login.png"/> <mx:RadioButton label="male" groupName="gender" selected="true" id="male"/> <mx:Image source="assets/female_login.png"/> <mx:RadioButton label="female" groupName="gender" selected="false" includeIn="defaultState"/> </mx:HBox> <mx:Spacer width="100%" height="7"/> <mx:HBox width="100%" horizontalAlign="right"> <mx:Image source="assets/dialog-warning.png" id="warning"/> <mx:Text color="#e60000" id="status" text="Text"/> <mx:Spacer width="100%"/> <mx:Button label="Connect" click="connect( event )" id="submit" width="110" height="34" icon="@Embed('assets/go-next.png')" includeIn="defaultState"/> </mx:HBox> </mx:VBox> <!-- chatState content --> <mx:VBox width="100%" height="100%" verticalGap="8" verticalAlign="middle" horizontalAlign="left" includeIn="chatState"> <mx:HDividedBox width="100%" height="100%" liveDragging="true"> <Chat:ChatTextarea editable="false" width="75%" height="100%" paddingLeft="3" focusAlpha="0" htmlText="{chat.chatHistory}"> </Chat:ChatTextarea> <mx:List height="100%" width="25%" itemRenderer="usersRenderer" dataProvider="{chat.dpUsers}"></mx:List> </mx:HDividedBox> <mx:HBox width="100%" verticalAlign="middle" horizontalAlign="center"> <mx:HBox width="75%" verticalAlign="middle" horizontalAlign="center" > <mx:ColorPicker id="picker" toolTip="Font color"/> <mx:TextInput width="100%" id="msg" paddingLeft="3" focusAlpha="0" keyUp="checkSend(event)" color="{picker.selectedColor}" /> <mx:Button label="Send" id="send" click="sendMsg()"/> </mx:HBox> <mx:HBox width="25%" verticalAlign="middle" horizontalAlign="center"> </mx:HBox> </mx:HBox> </mx:VBox> </mx:Panel> </mx:Application> And lastly, a Flex 4 button skin example, noting first the classic syntax, followed by the inline syntax.
BEFORE - Classic states syntax: <?xml version="1.0" encoding="utf-8"?> <Skin xmlns:mx="http://www.adobe.com/2006/mxml"> <states> <mx:State name="up" /> <mx:State name="over"> <mx:SetProperty target="{s}" name="color" value="0x6666BB" /> <mx:SetProperty target="{e2}" name="color" value="0xF0F0F0" /> </mx:State> <mx:State name="down" basedOn="over"> <mx:SetProperty target="{e1}" name="color" value="0xBBBBDD" /> <mx:SetProperty target="{e2}" name="color" value="0xBBBBDD" /> </mx:State> <mx:State name="disabled" > <mx:SetProperty target="{s}" name="color" value="0xAAAAAA" /> <mx:SetProperty target="{e2}" name="color" value="0xF0F0F0" /> </mx:State> </states> <content> <mx:Graphic left="0" top="0" right="0" bottom="0" scaleGridLeft="6" scaleGridTop="6" scaleGridRight="44" scaleGridBottom="14"> <mx:Rect width="50" height="20" radiusX="6" radiusY="6"> <mx:fill> <mx:SolidColor id="s" color="0x666666" /> </mx:fill> </mx:Rect> <mx:Rect width="48" height="18" x="1" y="1" radiusX="5" radiusY="5"> <mx:fill> <mx:LinearGradient rotation="90"> <mx:GradientEntry id="e2" color="0xFFFFFF" alpha="0.8" /> <mx:GradientEntry id="e1" color="0xDEDEDE" alpha="0.6" /> </mx:LinearGradient> </mx:fill> </mx:Rect> </mx:Graphic> <ContentHolder horizontalCenter="0" verticalCenter="1" left="10" right="10" content="{data.content}" layout="flex.layout.HorizontalLayout" /> </content> </Skin> AFTER - Inline states syntax: <Skin xmlns:mx="library:ns.adobe.com/flex/halo" xmlns:m="http://ns.adobe.com/mxml/2009" > <m:states> <m:State name="up" /> <m:State name="over"/> <m:State name="down"/> <m:State name="disabled" /> </m:states> <content> <mx:Graphic left="0" top="0" right="0" bottom="0" scaleGridLeft="6" scaleGridTop="6" scaleGridRight="44" scaleGridBottom="14"> <mx:Rect width="50" height="20" radiusX="6" radiusY="6"> <mx:fill> <mx:SolidColor color="0x666666" color.over="0x6666BB" color.down="0x6666BB" color.disabled="0xAAAAAA"/> </mx:fill> </mx:Rect> <mx:Rect width="48" height="18" x="1" y="1" radiusX="5" radiusY="5"> <mx:fill> <mx:LinearGradient rotation="90"> <mx:GradientEntry color="0xFFFFFF" color.down="0xBBBBDD" color.over="0xF0F0F0" color.disabled="0xF0F0F0" alpha="0.8" /> <mx:GradientEntry color="0xDEDEDE" color.down="0xBBBBDD" alpha="0.6" /> </mx:LinearGradient> </mx:fill> </mx:Rect> </mx:Graphic> <ContentHolder horizontalCenter="0" verticalCenter="1" left="10" right="10" content="{data.content}" layout="flex.layout.HorizontalLayout" /> </content> </Skin> B FeaturesStateful XML/E4X Nodes - There is an ask to allow descendants of XML and XMLList tags to support the new states syntax. If the feature is green-lit at a later date, an associated mini-spec will be published. Stateful Model Nodes - There is an ask to allow descendants of MXML datamodel (mx:Model) nodes to support the new states syntax. If the feature is green-lit at a later date, an associated mini-spec will be published. Enhanced Runtime API - As a fit and finish task, it would be prudent to update the runtime states API to follow closer to the way the new syntax works. e.g. A helper would be provided that would allow a developer to setPropertyForState(object, property, state) for instance. Or specifically set the include or exclude list for a given component instance. Essentially an API divorced from the notion of the current runtime States and Overrides model. When the work is done on this feature, a mini-spec will be circulated. Additional Implementation DetailsImplementation Design and ImplicationsA Phased ApproachAs mentioned previously, the states concept as first introduced in Flex 2.x and carried forward in Flex 3.0 will be promoted to a first-class MXML language feature for Flex 4.0. This means, for instance, that state-specific objects will no longer be limited to visual children (UIComponents). In order to get to a point where our tooling products can begin utilizing the new language features, we will phase in the functionality in stages.
Phase One Compiler and Framework ChangesCompiler ChangesThe MXML sub-compiler will be enhanced with direct support for states as follows:
SDK/API Changes
Nice To Have:
Prototype WorkThe bulk of the necessary compiler changes have been prototyped and passed along to the compiler team for review. An analysis of the changes with regards to performance was also done, using our stock performance automation tests, with good results. Compiler WorkPlease refer to the preceding Implementation Design and Implications section. Web Tier Compiler ImpactNot Applicable. Flex Feature DependenciesThis feature is dependent on any state-related features such as Overlays, Effects, Transitions. Backwards CompatibilitySyntax changesThe legacy states syntax will be deprecated in favor of what is detailed here. A mechanism will be provided to utilize the classic states syntax if desired but only by opting out of the Flex 4 model altogether (e.g. via -compatibility-version or by removing any MXML 2009 (Flex 4) namespace declarations). BehaviorNot applicable Warnings/DeprecationA deprecation related warning will be issued if the use of Override children of states are used within a Flex 4 document. AccessibilityNot Applicable. PerformanceThe new syntax as interpreted by the compiler results in generated code comparable to the current Flex 3 runtime states model, so no performance regressions or injections should be introduced (e.g. the IOverride based classes are still utilized at runtime to accomplish state changes). GlobalizationNot Applicable. LocalizationCompiler FeaturesThe following state syntax related error and warning messages have been added to compiler_en.properties and require translation: StateResolutionError - Cannot resolve state '$(name)'. AmbiguousStateFilterError - The includeIn and excludeFrom keywords may not be specified concurrently. ...more will be added here as necessary. There are no help description or linker message additions at this time. Framework FeaturesNot Applicable. Issues and Recommendations
DocumentationThe new states functionality represents a significant overhaul to the way stateful documents and components are authored with MXML. An equally as significant documentation revision around the view states feature is required, detailing not only the new language keywords, but also providing comprehensive examples. QASuggested focus areas and test cases to consider (not exhaustive):
|
|
| You must be logged in to comment. |
|---|
I second the first comment. If you use MXML to build you application nothing gets destroyed, large scale applications can end up with a lots of complex DisplayObjects existing all at the same time, until the application is closed.
After my first in-depth pass of the spec I have some concerns around the developer workflow and the possible complexity of the MXML generated with the new inline states. I agree that the current Flex state mechanism is hard to read, limited and can be overly complex to follow. Looking at the new proposed methodology I feel the solution has the potential to become just as complex, if not more so, and could make the code harder to follow for developers with larger components. An example of this kind of complex situation would be creating large forms that dynamically change their field structure dependent upon how the user answered previous fields in the form. On a project I worked on we relied heavily on states to solve this issue because we constantly had to show/hide fields and extend forms based on the user selections.
My first concern is that by moving into an inline methodology making changes from code view becomes harder to traverse and manage overtime. The new inline syntax requires the developer to look for state properties and tags within the whole of the MXML layout to determine what is being show when and where. One of the benefits of the current syntax is that each state node clearly (more or less) shows what happens when each state is selected. With the new syntax the developer has to comb over all the code and then attempt to find all the references that define state layout. In many situations this can be overcome by componentizing the code to help alleviate the complexity of the MXML but with large forms this is not necessarily an easy or viable solution.
My second concern is based around state inheritance. I see that I can set includeIn/excludeFrom to multiple states or groups, but this means that I have to track all of the reparenting inline vs. using the classic "basedOn" inheritance approach. A benefit of the inheritance model is that if state A handles a complex reparentaing structure and state B is a simple change to state A, a developer can simply state the changes in state B and then say extend from state A. With the new syntax, a developer has to track all the iterations of A and verify that B is added to all the state A changes and then make sure the B changes are applied.
As you can tell, both of my concerns are focused on codebase management. With the push of RIA development we are now creating code bases that have to grow, mature and scale over time. The focus of maintenance and team growth on a project is becoming more important for development teams and as new developers are brought into the code base, readability and ease of maintenance is very important. If a new developer was assigned to edit a form using the new layout they would have to review all of the MXML layout to determine both how it is structured and how it evolves with state changes. If this state management is defined outside of the layout then in some ways it is easier to determine what is changing and when. I fully realize that the current states model needs to be redesigned but I feel moving to 100% inline solution is not necessarily the best answer and possibly a hybrid approach could help help manage code readability.
Check the forum for discussion about states and layouts.
http://www.adobeforums.com/webx/.59b72791
Best,
Lance
HI
I been working with the new model for quite a while now and have found it a vast improvement all round.
One thing I wish I could do though, and this went for sdk3 also, is be able to use a const rather that a string literal in the state name in mxml. I just wish I could use something rather than "statename" in my code. Not at all sure how this would work mind you. I think what i want is just a new type of const that is just replaced at compile time with the value.
any ideas?
glenn

I would like to see a new feature added to states, perhaps a property, to force states to destroy all included components when they are not in the current state. Two reasons, to free up some memory and to allow the state to easily regain its original properties. The second one being more important to me. For example if I have a state with a bunch of text inputs and they user had entered text and left the state, then came back it is possible that i have unwanted text remaining. Or if I have a tab navigator that I had added tabs to with code and the user leaves the state, I now have to manually reset the tabs, where if the state destroyed everything then I would not have to worry about it at all. To me this is what would be expected when leaving a state anyway. In my last project I manually worked around this by adding things on the enterState event so I could destroy it myself, but it would be so much easier with a destroy = true property on the state.
I have previously added a feature request with key: SDK-15130
Thanks,
Shawn