Building components in MXML

来源:互联网 发布:java base64源码 编辑:程序博客网 时间:2024/06/11 07:25
 

Building components in MXML

In typical Adobe® Flex™ applications, you do not code the entire application in a single source code file. Such an implementation makes it difficult for multiple developers to work on the project simultaneously, makes it difficult to debug, and discourages code reuse.

Instead, you develop Flex applications by using multiple MXML and ActionScript files. This architecture promotes a modular design, code reuse, and lets multiple developers contribute to the implementation.

MXML components are MXML files that you reference by using MXML tags from within other MXML files. One of the main uses of MXML components is to extend the functionality of an existing Flex component.

For example, Flex supplies a ComboBox control that you can use as part of a form that collects address information from a customer. You can use a ComboBox to let the user select the Country portion of the address from a list of countries in the world. In an application that has multiple locations where a user can enter an address, it would be tedious to create and initialize multiple ComboBox controls with the information about all the countries in the world.

Flex follows the same principle; you create an MXML component that contains a ComboBox control with all country names defined within it. Then, wherever you must add a country selector to your application, you use your custom MXML component.

Link: You can also create Flex components in ActionScript. For more information, see the Building components in ActionScript Quick Start.

Creating a simple MXML component

You create an MXML component in an MXML file where the component's filename becomes its MXML tag name. For example, a file named CountryComboBox.mxml defines a component with the tag name of <CountryComboBox>.

The root tag of an MXML component is a component tag, either a Flex component or another MXML component. The root tag specifies the http://www.adobe.com/2006/mxml namespace. For example, the following MXML component extends the standard Flex ComboBox control. You can place custom components either in the root folder of your project or in a subfolder. Adobe recommends the latter location as a best practice. In this example, the custom component is placed in a folder called components. In the main application MXML file, you map this folder to a namespace called custom and use the fully-qualified tag name of <custom:CountryComboBox> to refer to the component.

Tip: In real-world applications, you may see custom components placed in a folder structure that uses a reverse domain name structure (e.g., xmlns:custom="com.adobe.quickstarts.customcomponents.*"). This convention avoids namespace conflicts between identically named components by different vendors. For example, two component libraries may each have a Map component that you want to use in your application. If one is in the com/vendorA/ folder and the other is in the com/vendorB/ folders, they do not conflict.

Example

components/CountryComboBox.mxml

<?xml version="1.0" encoding="utf-8"?><mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">    <mx:dataProvider>            <mx:String>United States</mx:String>        <mx:String>United Kingdom</mx:String>        <!-- Add all other countries. -->    </mx:dataProvider></mx:ComboBox>

Main application MXML file

<?xml version="1.0" encoding="utf-8"?><mx:Application     xmlns:mx="http://www.adobe.com/2006/mxml"    xmlns:custom="components.*"    width="220" height="115">    <custom:CountryComboBox/></mx:Application>

Result


To view the full source, right-click the Flex application and select View Source from the context menu.

Referencing properties and methods of a custom component

The CountryComboBox.mxml file specifies the ComboBox control as its root tag, so you can reference all of the properties and methods of the ComboBox control within the MXML tag of your custom component, or in the ActionScript specified in an <mx:Script> tag. For example, the following example specifies the rowCount property and a listener for the close event for your custom control.

Note: MXML files in Flex get compiled down into ActionScript classes before being converted into SWF bytecode that is run by the Adobe® Flash® Player. When you specify a root tag for a custom MXML component, you are actually having your component's class extend the class of the root component. This is why your custom component inherits the methods and properties of the root tag.

In the following example, the CountryComboBox MXML file gets compiled down into a class. The Flex naming convention is to use an initial cap on the component name, since it corresponds to a class name.

Example

components/CountryComboBox.mxml

<?xml version="1.0" encoding="utf-8"?><mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">    <mx:dataProvider>            <mx:String>United States</mx:String>        <mx:String>United Kingdom</mx:String>        <!-- Add all other countries... -->    </mx:dataProvider></mx:ComboBox>

Main application MXML file

<?xml version="1.0" encoding="utf-8"?><mx:Application     xmlns:mx="http://www.adobe.com/2006/mxml"    xmlns:custom="components.*"    width="270" height="170">    <mx:Script>        <![CDATA[            import flash.events.Event;            private function handleCloseEvent(eventObj:Event):void             {                status.text = "You selected: /r" + countries.selectedItem as String;            }            ]]>    </mx:Script>    <mx:Panel         title="Custom component inheritance"        paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10"    >        <custom:CountryComboBox             id="countries" rowCount="5"             close="handleCloseEvent(event);"        />        <mx:Text id="status" text="Please select a country from the list." width="136"/>            </mx:Panel></mx:Application>

Result


To view the full source, right-click the Flex application and select View Source from the context menu.

Creating composite MXML components

A composite MXML component contains multiple component definitions within it. To create a composite component, you specify a container as its root tag, and then add Flex components as children of the container.

The AddressForm component in the following example contains an address form created by specifying a Form container as the root tag of the component, and then defining several children of the Form container, including another custom component, the CountryComboBox.

Example

components/AddressForm.mxml

<?xml version="1.0" encoding="utf-8"?><mx:Form     xmlns:mx="http://www.adobe.com/2006/mxml"    xmlns:custom="components.*">   <mx:FormItem label="Name">        <mx:TextInput/>    </mx:FormItem>    <mx:FormItem label="Street">        <mx:TextInput/>    </mx:FormItem>    <mx:FormItem label="City">         <mx:TextInput/>    </mx:FormItem>    <mx:FormItem label="State/County">         <mx:TextInput/>    </mx:FormItem>    <mx:FormItem label="Country">         <custom:CountryComboBox/>    </mx:FormItem></mx:Form>

components/CountryComboBox.mxml

<?xml version="1.0" encoding="utf-8"?><mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">    <mx:dataProvider>            <mx:String>United States</mx:String>        <mx:String>United Kingdom</mx:String>        <!-- Add all other countries... -->    </mx:dataProvider></mx:ComboBox>

Main application MXML file

<?xml version="1.0" encoding="utf-8"?><mx:Application     xmlns:mx="http://www.adobe.com/2006/mxml"    xmlns:custom="components.*"    viewSourceURL="src/MxmlComponentComposite/index.html"    width="400" height="290">    <mx:Panel         title="Composite component"        paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10"    >        <custom:AddressForm />    </mx:Panel></mx:Application>

Result


If you include child tags of the root container tag in an MXML component file, you cannot add child tags when you use the component as a custom tag in another MXML component file. If you define an empty container in an MXML file, you can add child tags when you use the component as a custom tag. For example, the following use of the AddressForm is incorrect and does not compile:

<!-- Incorrect --><custom:AddressForm>    <mx:FormItem label="Post code">         <mx:TextInput/>    </mx:FormItem></custom:AddressForm>

If you must extend the functionality of a composite component, create a custom component that uses the composite component as its root tag.

Note: The restriction on child tags refers to the child tags that correspond to visual components. Visual components are subclasses of the UIComponent component. You can always insert tags for nonvisual components, such as ActionScript blocks, styles, effects, formatters, validators, and other types of nonvisual components, regardless of how you define your custom component.

To view the full source, right-click the Flex application and select View Source from the context menu.

Creating reusable MXML components

One of the common goals when you create MXML components is to create configurable and reusable components. For example, you might want to create MXML components that take properties, dispatch events, define new style properties, have custom skins, or use other customizations.

One design consideration when you create custom MXML components is reusability. That is, do you create a component that is tightly coupled to your application, or create one that is reusable in multiple applications?

A tightly coupled component is written for a specific application, often by making it dependent on the application's structure, variable names, or other details. If you change the application, you might have to modify a tightly coupled component to reflect that change. A tightly coupled component is often difficult to use in another application without rewriting it.

You design a loosely coupled component for reuse. A loosely coupled component has a well-defined interface that specifies how to pass information to the component, and how the component passes back results to the application.

You typically define the properties of a loosely coupled component to pass information to it. These properties, defined by using implicit accessors (setter and getter methods), specify the data type of the parameter value. In the following example, the CountryComboBox custom component defines a public useShortNames property that exposes the _useShortNames private property using the get useShortNames() and set useShortNames() accessor methods.

The Inspectable metadata tag for the _useShortNames private property defines an attribute that appears in the attribute hints and Tag inspector in Adobe® Flex™ Builder™. You can also use the metadata tag to limit the allowable values of the property.

Note: All public properties show up in MXML code hints and in the Property Inspector. If you have extra information about the property that will help code hints or the Property Inspector (such as enumeration values or that a String is actually a file path) then also add [Inspectable] metadata with that extra info.

MXML code hints and the Property Inspector properties all come from the same data, so if it shows up in one it should always show up in the other.

ActionScript code hints, on the other hand, do not require metadata to work correctly so you will always see the appropriate code hints in ActionScript depending on what scope you’re in. Flex Builder uses the public/protected/private/static, etc. identifiers plus the current scope to figure out what AS code hints to show.

The best practice for defining components that return information back to the main application is to design the component to dispatch an event that contains the return data. In that way, the main application can define an event listener to handle the event and take the appropriate action. You also use events in data binding. The following example uses the Bindable metadata tag to make useShortNames a bindable property. The implicit setter for the useShortNames property dispatches the change event that is used internally by the Flex framework to make data binding work.

Example

components/CountryComboBox.mxml

<?xml version="1.0" encoding="utf-8"?><mx:ComboBox xmlns:mx="http://www.adobe.com/2006/mxml">    <mx:Script>        <![CDATA[            private var countryArrayShort:Array = ["US", "UK"];            private var countryArrayLong:Array = ["United States", "United Kingdom"];                    // Determines display state. The inspectable metadata tag            // is used by Flex Builder 2             [Inspectable(defaultValue=true)]            private var _useShortNames:Boolean = true;                    // Implicit setter            public function set useShortNames (state:Boolean):void             {                // Call method to set the dataProvider based on the name length.                _useShortNames = state;                        if (state)                 {                    this.dataProvider = countryArrayShort;                 }                else                 {                    this.dataProvider = countryArrayLong;                }                                // Dispatch an event when the value changes                // (used in data binding.)                dispatchEvent(new Event("changeUseShortNames"));            }                        // Allow other components to bind to this property            [(event="changeUseShortNames")]            public function get useShortNames():Boolean             {                return _useShortNames;            }                         ]]>    </mx:Script></mx:ComboBox>

Main application MXML file

<?xml version="1.0" encoding="utf-8"?><mx:Application     xmlns:mx="http://www.adobe.com/2006/mxml"    xmlns:custom="components.*"    viewSourceURL="src/MxmlComponentAdvanced/index.html"    width="260" height="200">    <mx:Panel         title="Advanced custom components"        paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10"    >        <!-- Set a custom property on a custom component -->        <custom:CountryComboBox             id="countries"            useShortNames="false"        />                <!--             Use data binding to display the latest state            of the property.        -->        <mx:Label text="useShortNames = {countries.useShortNames}"/>                    <mx:ControlBar horizontalAlign="right">            <mx:Button                 label="Toggle Display"                click="countries.useShortNames = !countries.useShortNames;"            />        </mx:ControlBar>    </mx:Panel></mx:Application>

Result


To view the full source, right-click the Flex application and select View Source from the context menu.


For more information

For more information, see "Creating Custom MXML Components" in Creating and Extending Flex 2 Components.

About the author

Aral Balkan acts and sings, leads development teams, designs user experiences, architects rich Internet applications, and runs OSFlash.org, the London Macromedia User Group, and his company, Ariaware. He loves talking design patterns and writing for books and magazines. He also authored Arp, the open-source RIA framework for the Flash platform. Aral is generally quite opinionated, animated, and passionate. He loves to smile, and can even chew gum and walk at the same time.

原创粉丝点击