If you’re here because you’ve just heard about MXML for the first time and have NO clue what it is, you should start by reading Wikipedia’s MXML article.
Some Background
MXML is an XML-based language that is functionally equivalent to ActionScript. When MXMLC compiles MXML, first it translates it to ActionScript, then compiles that ActionScript into bytecode. In fact, if you pass the -compiler.keep-generated-actionscript argument to MXMLC, you can actually see the ActionScript that is generated from your MXML class. There’s a common misconception that using MXML requires using the Flex Framework, or that Flex is MXML and vice versa. Those are not true. MXML is a declarative language, like HTML. Flex is Adobe’s UI component framework. The two are not dependent on each other, which the South Park project demonstrates.
MXML in a Nutshell
Here’s an example of a default MXML file, which we’ll examine below:
<?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”
minWidth=”955” minHeight=”600“>
<fx:Declarations>
<!– Place non-visual elements (e.g., services, value objects) here –>
</fx:Declarations>
</s:Application>
Doctype Declaration
<?xml version=”1.0″ encoding=”utf-8″?>
The first line is required for all XML documents. It’s not unique to MXML and is essentially telling any parsers that read this file what to expect. You can basically take it for granted and not have to worry about it as long as you’re creating and working with MXML files within Flash Builder. If you’re using another editor, just make sure that you’re saving your files using utf-8 or you’ll run into nasty compilation problems.
Root Node
<s:Application minWidth="955" minHeight="600">
...
</s:Application>
There can only be 1 root node of any MXML document, and all other nodes must be contained by the root node. You can’t have 2 top level nodes in an MXML file, just like you can’t have 2 public classes in a single ActionScript class file. Also, the root node is normally a DisplayObjectContainer so you can place DisplayObjects within it. You could potentially create non-visual classes/components in MXML, but MXML’s strengths are laying out UI elements and rigging up event handling, so you would probably be better off using ActionScript in that case.
Namespace Declarations
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:bd="com.bdement.*"
Namespace declarations are equivalent to import statements in ActionScript, but they are a special attribute that must be present in the root node. The default namespace is http://ns.adobe.com/mxml/2009, which is required to make MXML “work,” regardless of whether you’re using the Flex Framework or not. xmlns:fx means “use a namespace called ‘fx,’” which lets you write tags that begin with <fx: and gives you access to all of the classes within that namespace. You can also import any package as a namespace by specifying it like the 2nd example.
The actual namespace (fx or mtvn, in the above lines) is arbitrary. For example, in the 2nd line I used “bd” as my namespace, but I could name it anything. Namespaces aren’t globally defined, so you can change them from class to class, although as a best practice you should name them consistently throughout your project.
Nodes
Every element within an (M)XML document is known as a node. Nodes are equivalent to declarations in ActionScript. Every time you specify a node like <ns:Object />, the resulting ActionScript will look like “new Object().”
Attributes
MXML gives you access to all of the public attributes exposed by a class. They’re set by declaring a value for them in MXML, like this:
<s:Application width="955" height="600">
This is the functional equivalent to the following ActionScript:
var myApp:Application = new Application();
myApp.width = 955;
myApp.height = 600;
Even in this simple example you can already see how MXML’s declarative structure is well-suited for “declaring” UI layouts.
Dynamic Attributes
Often you’ll want a particular value to change at runtime, and for that change to have some kind of effect on your UI. For example, a label that changes text when you click something.
To specify a dynamic attribute, wrap a reference to it in curly braces, as shown here:
<fx:Declarations> <fx:String id=”labelText“>My Label</fx:String>
</fx:Declarations>
<s:Label text=”{labelText}“/>
In this example we declared a String called “labelText,” and a Label that uses labelText’s value. The String is wrapped in a “Declarations” tag because it’s a non-visual element. All properties declared like this are given a public scope and are “bindable.” We’ll discuss more about data binding below.
As an alternative, you could also specify properties in script:
<fx:Script>
<![CDATA[
[Bindable(event="labelChanged")]
private var labelText:String = "My Label";
]]>
</fx:Script>
<s:Label text="{labelText}"/>
Here you’ll notice that instead of a Declarations tag, we used a Script tag, which contains a CDATA enclosure. The CDATA enclosure tells the MXML parser that content within the enclosure is “character data,” and will not follow (M)XML syntax.
Key Point: The key thing to know about data binding is that when you write a [Bindable] tag, always, 100% of the time, include a unique event name. If you don’t, your performance when using data binding will get really bad, really fast.
The reason is that if you don’t supply an event name, it defaults to “propertyChanged.” Then every time a property changes, Flash has to figure out which property changed, which becomes more expensive as you have more properties that are all dispatching that event. Also, if you view the ActionScript files generated from your MXML classes you can actually see how vastly different the generated code is when you do and don’t supply a property name.
Event Handlers
Event Handlers are specified in MXML very similarly to how attributes are specified, except they refer to a function rather than a property. For example:
<fx:Script>
<![CDATA[
protected function button1_clickHandler(event:MouseEvent):void
{
trace("Clicked!");
}
]]>
</fx:Script>
<s:Button id="button1" click="button1_clickHandler(event)"/>
You can probably see the connection pretty easily here, but notice that there are no curly braces in this case. Also notice that the magic variable “event” is being passed to the handler. “Event” is the naming convention used in MXML for the event that will be passed to your event handling function. You could also write event handlers like this, although I do not advocate it in all but the most trivial programs, I’m only showing this as a reference to show how the magic “event” comes out of nowhere:
<s:Button click="trace(event.type)"/>