Thinking Declaratively with MXML
There’s no mistaking that Flex 2 has been a historic release in the evolution of the framework. With Flex 3 closing in fast, there’s even more great features we can now use in our applications. Sometimes however, it is important to go back a remember some of the smaller features we may be overlooking. On a recent project I was reminded of the beauty of MXML itself, and the simple elegance that is markup.
MXML is one of those fundamentals of Flex that can sometimes catch developers off guard. The key is to remember that for the most part, every MXML tag and attribute corresponds directly to a Flex class and property respectively. When you declare
Note that there are exceptions such as
With that in mind, your assignment is to create a Canvas that has a DropShadowFilter on it at startup. You might think of a few ways to manage this task. The first solution that comes to most peoples minds is to catch the creationComplete event and then create and assign an instance of the filter. The second is to do the same steps, but all inline. These approaches will look something like the following snippet.
<mx:Script>
import flash.filters.DropShadowFilter;
public function doCreationComplete( event:Event ):void
{
myCanvas.filters = new Array( new DropShadowFilter() );
}
</mx:Script>
...
<mx:Canvas id="myCanvas" creationComplete="doCreationComplete( event )" />
Thinking declaratively however, it is important to remember that attributes of a tag are properties of a class. In this respect, why can’t we declare the “filters” property using MXML? Further, why not create an instance of DropShadowFilter declaratively as well. While we’re at it, we can even set all the filter properties declaratively. This approach looks something like the following snippet.
<mx:Canvas>
<mx:filters>
<mx:Array>
<mx:DropShadowFilter blurX="3" blurY="6" color="0x000000" />
</mx:Array>
</mx:filters>
</mx:Canvas>
If after reading these code samples, you find yourself thinking that this is obvious, rest assured that I’ve seen even the best Flex developers jump through hoops to solve a problem in script that might have otherwise been accomplished declaratively. In looking back through some of my own past code, I’ve even seen places where I’ve use the script approach where the declarative approach made more sense.
Okay, so where are some other areas where thinking declaratively can really make a big difference?
Probably the next most common situation where I see script being used where MXML would work better is when developers use the Flex charting. The Flex charts (improved in Flex 3) provide a wealth of flexibility in the appearance. Strokes, fill, axes, series are all classes that can be creatively declaratively just as easily as they can be through script.
<mx:CartesianChart id="chart" width="100%" height="100%">
<mx:horizontalAxis>
<mx:DateTimeAxis
id="dAxis"
displayName="Time"
autoAdjust="{adjust.selected}"
displayLocalTime="{local.selected}" />
</mx:horizontalAxis>
<mx:horizontalAxisRenderer>
<mx:AxisRenderer
minorTickPlacement="outside"
minorTickLength="3">
<mx:minorTickStroke>
<mx:Stroke color="#BBCCDD" weight="1" />
</mx:minorTickStroke>
</mx:AxisRenderer>
</mx:horizontalAxisRenderer>
<mx:dataProvider>{dataSet}</mx:dataProvider>
<mx:series>
<mx:ColumnSeries
displayName="Bannana Sales"
xField="dt"
yField="F0" />
</mx:series>
</mx:CartesianChart>
What is interesting is that it is equally common to find developers having problems going the other way - making the connection between all those tags and the class/properties they represent. As an example, I’ve often been asked how to add columns to a DataGrid from script. This is usually because the developer has disconnected the markup from the class.
<mx:Script>
...
import mx.controls.dataGridClasses.DataGridColumn;
public function doCreationComplete( event:Event ):void
{
var cols:Array = new Array();
var col:DataGridColumn = null;
for( var c:Number = 0; c < 5; c++ )
{
col = new DataGridColumn();
col.headerText = "Stuff " + c;
cols.push( col );
}
grid.columns = cols;
}
...
</mx:Script>
...
<mx:DataGrid id="myGrid" creationComplete="doCreationComplete( event )" />
Finally, I’ll leave you with a somewhat more fringe case, that has application nonetheless. How do you apply a mask to a display object? There’s clearly a mask property, but how does that manifest itself in markup? In the following example, I’ve applied a mask object via MXML.
<mx:Canvas width="100" height="100" mask="{myMask}" />
<mx:Canvas id="myMask" width="100" height="100" borderSkin="skins.MyStarMaskSkin" />
What’s particularly interesting is that the only script is in drawing the border skin of the mask object. There’s been some discussion of the forthcoming MXMLG, which I think really starts to make the declarative side of Flex even more compelling. In the meantime, I encourage you to step back occasionally, and think about what the humble feature of MXML can do for you.
January 15th, 2008 at 5:47 pm
I think the adding columns example is incorrect. You can’t just myGrid.columns.push(…) because the accessor on columns returns a copy of the Array. You need to build another array and then assign it over the columns array.
var col:Array = myGrid.columns;
col.push( col );
myGrid.columns = col;
January 15th, 2008 at 6:49 pm
Whoops!
The code in the article has been updated.
Thanks,
Kevin
January 28th, 2008 at 1:57 pm
Hi Kevin,
As usual, a nice post and I also learnt more from this.
I have been doing some work using html/css/javascript and been following semantic-html and Layer Semantic Markup approach.
Just wondering, how would you thing semantic in context of mxml? MXML is very powerful because you can have structure as well as style/effects within in it? That surely also causes the bad-apps/design, if best-practices are not considered.
I have been thinking, how things should have been designed so that RIA applications developed using MXML/ActionScript/CSS can be progressively enhanced or gracefully degraded (for FlashLite etc).
For example: If there were a subset of MXML to represent semantic/structure of application, another subset to add presentation (CSS is there but limited in some sense) and last subset to add behavior/actions using actionscript..
It would have been easier to run RIAs on FlashLite by just taking care of presentation and actionscript… Think each part linked as different swfs?
I might not be making sense, just looking at standards already established and trying to draw some parallels… How can we make one app that works on most of the devices…
Flex framework needs to separate entire styles related stuff from it’s component, it would become lighter and more flexible?
I hope, you get the sense… Since you are into both worlds (AJAX/DHTML and Flex), would love to hear your thoughts as a comment or new post
Thanks
-abdul
January 28th, 2008 at 4:34 pm
It’ll be a while before Flex 4 comes out and we get MXMLG but lately I have fallen in complete and utter love with degrafa.
Over the past month, I’ve been writing all my skins in mxml with degrafa and using markup instead of ActionScript makes the code so easy, intuitive, elegant and beautiful.
Check this out and you’ll know what I mean
http://samples.degrafa.com/SphereSkinSample/SphereSkinSample.html
May 17th, 2008 at 7:14 am
Thanks Kevin Hoyt for this update!
Simon G.