<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Alex Uhlmann</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/" />
<modified>2009-01-25T16:32:31Z</modified>
<tagline></tagline>
<id>tag:weblogs.macromedia.com,2009:/auhlmann//62</id>
<generator url="http://www.movabletype.org/" version="3.16">Movable Type</generator>
<copyright>Copyright (c) 2009, auhlmann</copyright>
<entry>
<title>Adobe TV: Agile Testing of Enterprise RIAs with Flex and LiveCycle ES</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2009/01/adobe_tv_agile.html" />
<modified>2009-01-25T16:32:31Z</modified>
<issued>2009-01-22T20:11:27Z</issued>
<id>tag:weblogs.macromedia.com,2009:/auhlmann//62.15182</id>
<created>2009-01-22T20:11:27Z</created>
<summary type="text/plain">Adobe TV now hosts the full MAX 2008 session about Agile Testing of Enterprise RIAs with Flex and LiveCycle ES from Herve Dupriez and me. Herve talks about the LCES part and I about Flex. This presentation focuses on how...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Testing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>Adobe TV now hosts the full MAX 2008 session about <a href="http://tv.adobe.com/#vi+f15384v1033">Agile Testing of Enterprise RIAs with Flex and LiveCycle ES</a> from Herve Dupriez and me. Herve talks about the LCES part and I about Flex.</p>

<p>This presentation focuses on how your architectural design could look like to make agile testing feasible and efficient. It’s explaining principles we’ve been following at projects that can make Test Driven Development of RIAs a reality.</p>

<p>It also touches upon code coverage tooling available for Flex and its recommended usage. Checkout <a href="http://code.google.com/p/flexcover/">Flexcover</a>, the open source code coverage tool. Flexcover was created by <a href="http://joeberkovitz.com/blog/">Joe Berkovitz</a> and some months ago I joined his efforts after I developed an internal tool that followed another approach using only Flash Player APIs. Joe's approach is actually customizing the open source Flex compiler and can therefore achieve object code branch coverage. Join the Flexcover project to keep it going!</p>

<p>During the presentation I’ve mentioned further information about IoC frameworks that my collegue Ed Eustace already <a href="http://code.google.com/p/flex-ioc-examples">put online</a>. Also, Michael Labriola’s presentation at MAX 08 “Testing Flex Applications” spend more time comparing different testing tools. This is not online at Adobe TV yet, but upcoming.</p>

<p>Also check out the presentations from my other colleagues at Adobe Professional Services:</p>

<ul>
<li><a href="http://tv.adobe.com/#vi+f15384v1016">RIA Development with Cairngorm - Tips from the Experts
from Peter Martin and Eric Garza</a></li>
<li>Architectural Best Practices for Flex and LiveCycle ES Application from Steven Webster and Tunde Turner</li>
<li><a href="http://tv.adobe.com/#vi+f15383v1064">Television on AIR - Creating Custom Media Player Experiences from Xavi Beumala Segura, John Bennett Kyle Glossy and Mark Hirsch</a></li>
<li>
<a href="http://tv.adobe.com/#vi+f15384v1017">Delivering Collaborative Apps with AIR and LiveCycle Data Services from Alistair McLeod and Xavier Agnetti</a>
</li>
<li><a href="http://tv.adobe.com/#vi+f15383v1051">Lazy Innovation: Strategy for the Design of Innovative User Experiences from George Neill and Jerome Doran</a></li>
</ul>]]>

</content>
</entry>
<entry>
<title>Download Flight Effect</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2009/01/download_flight.html" />
<modified>2009-01-22T20:37:50Z</modified>
<issued>2009-01-22T19:54:58Z</issued>
<id>tag:weblogs.macromedia.com,2009:/auhlmann//62.15181</id>
<created>2009-01-22T19:54:58Z</created>
<summary type="text/plain">Imagine an airplane that takes off the ground, flies across a distance and lands at an arbitrary destination. This post will explain how to do the same in Flex, using the Flight effect, which you can download here. Before I...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Effects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>Imagine an airplane that takes off the ground, flies across a distance and lands at an arbitrary destination. This post will explain how to do the same in Flex, using the Flight effect, which you can download here.</p>

<p>Before I explain any further, take a look at <a href="http://alex-uhlmann.de/flash/adobe/blog/store_with_flighteffect/">a running example</a>. I’ve taken the Cairngormstore and added the Flight effect to the point when the user wants to add a product to his shopping cart. Simply click on the “Add to Cart” button to see the effect playing.</p>

<p><img alt="store_with_flighteffect.JPG" src="http://weblogs.macromedia.com/auhlmann/archives/store_with_flighteffect.JPG" width="504" height="613" /></p>

<p>The key here is that the product doesn’t immediately appear in the shopping cart DataGrid control as the user presses the “Add to Cart” button. Instead, the Flight effect animates the product into the shopping cart control. Download it <a href="http://weblogs.macromedia.com/auhlmann/archives/flightEffect.zip">here</a>.</p>]]>
<![CDATA[<p>The implementation of this effect is surly too exaggerated for any real life application and I strongly recommend consulting your User Experience experts before using an effect such as this. However, if applied responsibly, animating visual state changes of your applications instead of just setting and using movement to manage the user’s attention can help with cognition. Consult people who understand user experience design before using effects like this.</p>

<p><strong>What is it?</strong></p>

<p>The flight effect moves a display object either along a straight line or a quadratic bezier curve. While playing the display object is being scaled up and down to mimic a flight object taking off and landing (with using a good bit of imagination)</p>

<p>I’ll explain the usage of this effect with a simpler example. This flight effect is a standard Flex effect, so you can use it in ActionScript, Behaviours, Transitions etc. The following example shows a login panel moving and rotating to the bottom right corner of the screen. It plays in a Canvas container and all we need to set up the effect is to apply a simple Transition tag to the view state change.<br />
<pre><br />
   &lt;mx:states&gt;<br />
      &lt;mx:State name="stateA"&gt;<br />
         &lt;mx:SetProperty target="{ login1 }" name="x" value="519"/&gt;<br />
         &lt;mx:SetProperty target="{ login1 }" name="y" value="323"/&gt;<br />
      &lt;/mx:State&gt;<br />
   &lt;/mx:states&gt;</p>

<p>   &lt;mx:transitions&gt;<br />
      &lt;mx:Transition effect="{ mover }" /&gt;<br />
   &lt;/mx:transitions&gt;<br />
   <br />
   &lt;mx:Sequence id="mover"&gt;<br />
      &lt;mxeffects:Flight <br />
         target="{ login1 }" <br />
         duration="2000" <br />
         maximumHeight="2" <br />
         rotate="true" /&gt;     <br />
   &lt;/mx:Sequence&gt;<br />
   <br />
   &lt;sides:Login <br />
      id="login1" <br />
      change="currentState = ( currentState == 'stateA' ) ? '' : 'stateA';"/&gt;<br />
</pre></p>

<p>BTW: Behind the scences, Flight uses a MoveOnQuadCurve effect that I ported from <a href="http://alex-uhlmann.de/flash/animationpackage/">AnimationPackage</a>. You could also use this effect without Flight if you wish.</p>

<p><strong>Flying across Flex container constraints</strong></p>

<p>Since we use a Canvas container in the example above, the Panel component can be moved to arbitrary positions within that Canvas container. However, in some applications, like in the Cairngormstore sample application, we need to move across different containers. How I did this in Cairngormstore and how you can do the same in your applications will be the topic of the next section.</p>

<p><strong>Flight Effect Applied</strong></p>

<p>As pointed out in the end of the last section, the effect by itself isn’t enough if you want display objects to move across Flex containers. This section will show how I achieved this in the Cairngormstore sample application and how you can apply the same concept to your application. You can by the way also use a simple Move effect using the same concept.</p>

<p>But before I start with any implementation, let me please remind you on using this effect responsibly. As with many effects, applied in the wrong way, effects can dramatically reduce the user experience instead if increasing it. Consult a User Experience expert before you apply it to your application.</p>

<p><strong>10000 feet overview</strong></p>

<p>In order to let the flight object (our airplane) cross Flex container boundaries we need professional assistance. A FlightCaptain object can help us with </p>

<ul>
<li>starting up our airplane.</li>
<li>finding our origin and destination coordinates.</li>
<li>flying the airplane according to a specified route.</li>
</ul>

<p>If this sounds all a bit strange to you, follow me with a little example. </p>

<p>Let’s fly one box from the black area to the red area.</p>

<p>With clicking the button, the user tells the FlightCaptain to get going:</p>

<pre>
            var captain : FlightCaptain = new FlightCaptain();            
            captain.airplaneType = Login;         
            captain.origin = login;
            captain.destination = destinationContainer;
            captain.play();
</pre>

<p>We tell him the type of plane we would like him to use (a custom Panel component of type Login), and the start and destination locations.</p>

<p>In the above example the FlightCaptain creates a new airplane of type Login, flies it to the destination location and once landed, he removes it (he would put it back into the hanger)</p>

<p>But in your specific application, you might want the FlightCaptain to move not just copy the display object that we tell him is the airplane.</p>

<p>We can do that with removing the display object specified with the origin property when FlightCaptain is taking off…</p>

<pre>
  captain.addEventListener( TweenEvent.TWEEN_START, acualTakeOffTime );
</pre>

<p>…and adding it to the display list once the captain lands.</p>

<pre>
  captain.addEventListener( TweenEvent.TWEEN_START, acualTakeOffTime );
</pre>

<p>Important to note here is that we use the TweenEvent.TWEEN_START event. This event is triggered when the first tween update is performed, meaning we are sure our airplane is in the air (popup is created) and we can safely remove our old display object.</p>

<p>We also have access to the route our FlightCaptain is taking. His route property is a Flight effect. We can i.e. tell him to take a long way round with modifying the xBetween and yBetween properties of route. </p>

<pre>
captain.flight.yBetween = 1000;
</pre>

<p>Here’s the full code:</p>

<pre>

<p><br />
&lt;?xml version="1.0" encoding="utf-8"?&gt;<br />
&lt;mx:Application <br />
	xmlns:mx="http://www.adobe.com/2006/mxml" <br />
	xmlns:sides="view.sides.*" <br />
	layout="horizontal"&gt;<br />
	<br />
   &lt;mx:Script&gt;<br />
   	&lt;![CDATA[<br />
   		import mx.events.TweenEvent;<br />
   		import mx.events.EffectEvent;<br />
   		import mx.core.Container;<br />
   		import view.sides.Login;<br />
   		import com.adobe.ac.mxeffects.FlightCaptain;<br />
         <br />
         private var originContainer : Container;<br />
         private var destinationContainer : Container;<br />
         <br />
         private function fly() : void<br />
         {<br />
         	destinationContainer = ( login.parent == blackBox ) ? redBox : blackBox;<br />
            originContainer = ( destinationContainer == blackBox ) ? redBox : blackBox;<br />
            <br />
            var captain : FlightCaptain = new FlightCaptain();            <br />
            captain.addEventListener( TweenEvent.TWEEN_START, acualTakeOffTime );<br />
            captain.addEventListener( TweenEvent.TWEEN_END, acualLandingTime ); <br />
            captain.airplaneType = Login;         <br />
            captain.origin = login;<br />
            captain.destination = destinationContainer;<br />
            captain.configureFlight();<br />
            captain.play();<br />
         }<br />
         <br />
         private function acualTakeOffTime( event : TweenEvent ) : void<br />
         {<br />
         	originContainer.removeChild( login );<br />
         }<br />
         <br />
         private function acualLandingTime( event : TweenEvent ) : void<br />
         {<br />
         	destinationContainer.addChild( login );<br />
         }<br />
   	]]&gt;<br />
   &lt;/mx:Script&gt;<br />
   &lt;mx:Canvas <br />
   	id="blackBox" <br />
   	backgroundColor="black" <br />
   	width="400" height="400"<br />
   	&gt;<br />
   	&lt;sides:Login <br />
   		id="login" left="8" top="8" <br />
   		change="fly()" /&gt;<br />
   &lt;/mx:Canvas&gt;<br />
   <br />
   &lt;mx:Canvas <br />
   	id="redBox" <br />
      backgroundColor="red" <br />
      width="400" height="400"/&gt;<br />
      <br />
&lt;/mx:Application&gt;<br />
</pre><br />
<strong><br />
Behind the captain’s curtain</strong></p>

<p>How does the FlightCaptain do his job? This section explains how you he manages to fly across Flex containers. </p>

<p>Let’s first take a look into FlightCaptain’s play method. </p>

<p>At first we get the airplane of the specified type…</p>

<pre>
airplane = getPlaneFromHanger();
</pre>

<p>…which simply creates a popup using PopUpManager.</p>

<pre>
private function getPlaneFromHanger() : IFlexDisplayObject
{
return PopUpManager.createPopUp( DisplayObject( Application.application ), typeOfPlane );
}
</pre>

<p>Then he finds out about the actual coordinates where he is expected to start and land.</p>

<pre>
var originCoords : Point = findOriginCoords( origin );		
var destinationCoords : Point = findDestinationCoords( destination );         
</pre>	

<p>This translates the local coordinates of our specified origin and destination display objects into a global coordinate system. We need to do this because our origin and destination display objects are potentially deeply nested somewhere between various Flex containers. Our FlightCaptain prefers to fly high up in the sky (in popup coordinate space, which understands global coordinates), therefore we need to translate.</p>

<pre>
private function findOriginCoords( origin : DisplayObject ) : Point
{
		var originTopLeft : Point = new Point( 0, 0 );
		originTopLeft = origin.localToGlobal( originTopLeft );
		return originTopLeft;
}
		
private function findDestinationCoords( destination : DisplayObject ) : Point
{
	var destinationTopLeft : Point = new Point( 0, 0 );
	destinationTopLeft = destination.localToGlobal( destinationTopLeft );
	return destinationTopLeft;
}
</pre>

<p>Have fun <a href="http://weblogs.macromedia.com/auhlmann/archives/flightEffect.zip">with it</a>!</p>]]>
</content>
</entry>
<entry>
<title>Lighted Distortion Effects and Tour de Flex</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2009/01/lighted_distort.html" />
<modified>2009-01-25T16:36:34Z</modified>
<issued>2009-01-22T19:36:10Z</issued>
<id>tag:weblogs.macromedia.com,2009:/auhlmann//62.15180</id>
<created>2009-01-22T19:36:10Z</created>
<summary type="text/plain">There’s a slightly updated version of the distortion effects shipping with the amazing Tour de Flex AIR application (flex.org/tour). This update adds another feature that our User Experience team found “adding to reality”. Lighting! Lighting works on all effects supplied....</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Effects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>There’s a slightly updated version of the distortion effects shipping with the amazing <a href="http://www.flex.org/tour">Tour de Flex AIR application</a> (<a href="http://www.flex.org/tour">flex.org/tour</a>). This update adds another feature that our User Experience team found “adding to reality”. Lighting!</p>

<p>Lighting works on all effects supplied. Here’s how it looks like on CubeRotate:</p>

<p><img alt="lightingcube1.gif" src="http://weblogs.macromedia.com/auhlmann/archives/lightingcube1.gif" width="296" height="212" /></p>

<p>But see all the effects in action <a href="http://www.alex-uhlmann.de/flash/adobe/blog/distortionEffects/effectCube/">from this example</a>. Download it <a href="http://weblogs.macromedia.com/auhlmann/archives/DistortionEffects.zip">here</a> directly.</p>]]>
<![CDATA[<p>The above version is still Flash Player 9 and Flex, 2, 3 compatible. If you can target Flash Player 10, make sure you check out the new 3D functionality, which makes effects such as these easier to do and more efficient.</p>

<p>Also, <a href="http://www.tink.ws/blog/">Tink</a> has released a new Flex effects library (<a href="http://www.efflex.org">efflex.org</a>) that also adds distortion effects. I’d definitely recommend checking out Tink’s work or even considering participating in this new exciting open source project. Great work Tink!</p>

<p><strong><br />
Here is How You Can Use it:</strong></p>

<p>Generally you define a lighting source. When your lighting source is located on the top left then the effects will turn brighter once your display object turns towards the top or left.</p>

<p>To do that you just have to set two properties </p>

<ul>
<li>-horizontalLightingLocation takes either a LEFT and RIGHT value (use DistortionConstants for setting this or FlexBuilder’s code hints).</li>
<li>-verticalLightingLocation takes either TOP or BOTTOM.</li>
<li>-lightingStrength is an optional property, which defaults to 7.5 if not set.</li>
</ul>

<p>Lighting is turned off by default. To activate it you just need to set either the horizontalLightingLocation, verticalLightingLocation or both properties.</p>]]>
</content>
</entry>
<entry>
<title>Distortion Effects - Updated</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2007/03/distortion_effe.html" />
<modified>2009-01-25T16:38:19Z</modified>
<issued>2007-03-05T00:37:52Z</issued>
<id>tag:weblogs.macromedia.com,2007:/auhlmann//62.13286</id>
<created>2007-03-05T00:37:52Z</created>
<summary type="text/plain">Here’s a new version of the distortion effects. Thanks for all your tremendous feedback on the previously released distortion effects. Some of that feedback is now included in this updated version. This version adds various features and updates. Here’s an...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Effects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>Here’s a new version of the distortion effects.</p>

<p>Thanks for all your tremendous feedback on the <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/11/download_distor.cfm">previously released distortion effects</a>. Some of that feedback is now included in <a href="http://weblogs.macromedia.com/auhlmann/archives/DistortionEffects.zip">this updated version</a>. This version adds various features and updates. Here’s an excerpt:</p>

<p><strong>Exceed Bounds</strong></p>

<p>Much of the feedback I’ve received was about making the flip effect more realistic. The hint was to let its bounds overlap while the flip effect is coming towards the user. (flipping in). The new exceedBounds property on the Flip effect does exactly that and is now turned on by default!</p>

<p><img alt="exceedBounds.gif" src="http://weblogs.macromedia.com/auhlmann/archives/exceedBounds.gif" width="306" height="268" /></p>

<p><br />
<strong>Pop mode UP</strong></p>

<p>The Pop effect now has an additional mode. The default mode is DOWN, which pops a display object off a stack/pile, away from the user. The new UP mode pops it towards the user.</p>

<p><img alt="popDown.gif" src="http://weblogs.macromedia.com/auhlmann/archives/popDown.gif" width="433" height="318" /></p>]]>
<![CDATA[<p><strong>Scaling Support</strong></p>

<p>Some of you have experienced issues with distortions done on display objects that are below other display objects, which are being scaled. You can scale display objects either using UIComponent’s or DisplayObject’s scaleX, scaleY properties or with modifying the DisplayObject’s transform matrix (a and d properties). This version of the distortion effects supports any scalings applied to any parent display objects in your display list.</p>

<p><br />
<strong>Support of More Environments</strong></p>

<p>My goal with these effects always was to support all possible environments where you can use these effects and distortions. With environments I meant i.e. using distortions or utilities in a non Flex framework environment, using only the Flash Player API. But also the use in different Flex framework containers and effect setups, i.e. States and Transitions, hideEffects, ActionScript effects, with ViewStacks, custom containers etc. </p>

<p>This version increases the number of environments to support to the point that I currently haven’t heard of an environment that isn’t supported. If you have one, let me know and feel free to send me an isolated example and I’ll try to help out.</p>

<p>This version added support for some States and Transition usages i.e. with supporting multiple siblings and improves error handling in case views cannot be initialized.</p>

<p>See them in action <a href="http://www.alex-uhlmann.de/flash/adobe/blog/distortionEffects/effectCube/">here</a>.</p>

<p>Download <a href="http://weblogs.macromedia.com/auhlmann/archives/DistortionEffects.zip">here</a>!</p>]]>
</content>
</entry>
<entry>
<title>Creating a Popup in a Cairngorm Architecture</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2007/02/creating_a_popu.html" />
<modified>2007-02-12T15:45:15Z</modified>
<issued>2007-02-12T14:02:14Z</issued>
<id>tag:weblogs.macromedia.com,2007:/auhlmann//62.13127</id>
<created>2007-02-12T14:02:14Z</created>
<summary type="text/plain">Often I see this question coming up: &quot;How should I best create a popup in my Cairngorm application?&quot; I think of creating a popup control as something only views should be concerned about. It’s like creating other view components, managing...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Cairngorm</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>Often I see this question coming up:</p>

<blockquote>"How should I best create a popup in my Cairngorm application?"</blockquote>

<p>I think of creating a popup control as something only views should be concerned about. It’s like creating other view components, managing states of view components or effects. Therefore this question isn't just about creating popups, instead it's about how to invoke methods that belong to the view. (BTW: I often hear from our User Experience team that they try to prevent popups where possible)</p>]]>
<![CDATA[<p>First and foremost, I’d try to let your views directly call a method that dispatches a popup.</p>

<p>However, most of the use cases that came up when questions like the above have been asked are slightly more complex. Users for example want to create a popup in a completely different part of the application. Or they receive an asynchronous remote service response, only want to react to the user with a popup at that point in time and work in a context where no view references are available, such as a typical Cairngorm Command.</p>

<p>Some users have created the code needed for creating a popup directly in the result method of a command or in a model object that’s been called by the result method of a command.</p>

<p>Sticking to my above rule; that only views should be concerned about popups, I think both solutions are not the optimal approach. A command should just be an encapsulated request to your model and a model itself should also not be concerned about any UI behavior. I’d argue we need to tell the model about the state change that has just occurred in your application, but in a model context. For example you might set a loggedIn property on a Login model object to true in order to signal that the login process was successful after a positive remote service response.</p>

<p><strong>So, how can our views react to that state change in our model?</strong></p>

<p>In a typical Cairngorm application, we may bind UI controls to properties of our model objects. But for creating a Popup control, there’s no UI component where we can bind to. How do we best let a view invoke a view related method after a certain state change in our model occurred?</p>

<p>Let’s take a step by step approach using a very simple Cairngorm application, that retrieves a list of employees and displays them in a popup after successful retrieval. </p>

<p>Please do ask your UX team if something like this is really a good idea in a real world application. For the sake of this example we don’t care about the user experience here!</p>

<p>This step by step tutorial will walk you through the relevant parts. You can <a href="http://www.alex-uhlmann.de/flash/adobe/blog/cairngormpopup/">see and download</a> (via right click > View Source) the complete application here. Let's go:</p>

<p><strong>Dispatch a Cairngorm Event.</strong></p>

<p>Let the view dispatch a user gesture via a Cairngorm Event in order to trigger the remote service:</p>

<p>On a mx:Button’s click event, the getEmployees method dispatches the Cairngorm event:</p>

<p>Excerpt from GetEmployeesCommand.as:</p>

<pre>
private function getEmployees() : void
{
  	var event : GetEmployeesEvent = new GetEmployeesEvent();
  	event.employees = model.employees;
  	CairngormEventDispatcher.getInstance().dispatchEvent( event );
}
</pre>

<p><strong>Call and handle the remote service and modify your model.</strong></p>

<p>The handling GetEmployeesCommand’s execute method calls a server side method. Its result method modifies the model. Here, it retrieves the model object Employeee via the ModelLocator.</p>

<p>Excerpt from GetEmployeesCommand.as:</p>

<pre>
private var employees : Employees;
		
public function execute( event : CairngormEvent ) : void
{
	employees = GetEmployeesEvent( event ).employees;
	employees.hasEmployees = false;
			
	var delegate : EmployeeDelegate = new EmployeeDelegate( this );
	delegate.getEmployees();
}
		
public function result( event : Object ) : void
{
	employees.employees = IList( event.result );
	employees.hasEmployees = true;
}
</pre>

<p>Employees.as:</p>

<pre>
package com.adobe.cairngorm.samples.popup.model
{
	import mx.collections.IList;
	
	public class Employees
	{
		[Bindable]
		public var employees : IList;
		[Bindable]
		public var hasEmployees : Boolean;		
	}
}
</pre>

<p>Note that we modify the hasEmployees property of the Empoyees model object.</p>

<p><strong>Let the view react react for you!</strong></p>

<p>And here comes the crux: You can use the mx:Binding tag or the <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/using_binding_s.cfm">Observe/ObserveValue tag</a>  to invoke a view method, once the hasEmployees Boolean value changes.</p>

<p>I’d recommend using the ObserveValue tag to listen to a specific value of a state change of your model. More precisely, you can bind the source property of it to the bindable hasEmployees property of your model object Employees.</p>

<pre>
&lt;ac:ObserveValue 
	source="{ model.employees.hasEmployees }" 
	handler="{ createEmployeeList }" 
	value="{ true }"/&gt;
</pre>

<p>You could have also used the Observe tag to listen all updates of the hasEmployees property. For more information, check <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/using_binding_s.cfm">this</a> out.<br />
The ObserveValue tag above will invoke the createEmployeeList method defined in a Script block of the same MXML file. This method will invoke the popup.</p>

<pre>
private function createEmployeeList() : void
{
	var application : DisplayObject = DisplayObject( Application.application );
	var popup : IFlexDisplayObject = PopUpManager.createPopUp( application, EmployeeList, true );			
	PopUpManager.centerPopUp( popup );
	var concretePopup : EmployeeList = EmployeeList( popup );
	concretePopup.employees = model.employees;
}
</pre>

<p>That's it! Through a state change in your model, you view has reacted. Furthermore, you can now let many other objects observing this particular state of your model and they can all act independently.</p>

<p>Cheers!</p>]]>
</content>
</entry>
<entry>
<title>Best Practice: Code Behind versus MXML Script Blocks versus View Helper</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2007/02/best_practice_c.html" />
<modified>2007-02-04T11:12:37Z</modified>
<issued>2007-02-04T10:56:53Z</issued>
<id>tag:weblogs.macromedia.com,2007:/auhlmann//62.13080</id>
<created>2007-02-04T10:56:53Z</created>
<summary type="text/plain">Often I see the question coming up on whether to use MXML Script blocks, Code Behind or Helper classes. I think the question behind the question we&apos;re addressing here is not whether to use Code Behind, MXML Script blocks or...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Best Practice</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>Often I see the question coming up on whether to use MXML Script blocks, Code Behind or Helper classes.</p>

<p>I think the question behind the question we're addressing here is not whether to use Code Behind, MXML Script blocks or View Helpers, but is actually where is it best to place functionality in a Flex application.</p>

<p>But first of all, let’s have a quick rundown on what Code Behind, View Helper and MXML Script blocks actually are:</p>]]>
<![CDATA[<p>If you come from the ASP world you might be familiar with Code Behind, if not more information about Code Behind can be found <a href="http://livedocs.macromedia.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=ascomponents_147_13.html">at the livedocs</a> and <a href="http://www.adobe.com/devnet/flex/quickstart/building_components_using_code_behind/">at the devnet</a>.</p>

<p>The Script block is the part of an MXML file dedicated to ActionScript methods and properties.</p>

<p>For example:</p>

<pre>
&lt;mx:Script&gt;
	private function doSomething() : void
{
		blah…
}
&lt;/mx:Script&gt;
</pre>

<p>For a View Helper, people might have different definitions. Personally, I’d define a View Helper as an ActionScript class that a MXML can call and listen to directly. Typically it contains the code related to the accompanying MXML and might even simply contain the functionality that developers otherwise would put in MXML Script blocks. It can have references to the view, such as the Cairngorm View Helper (which are not a recommended approach). I’d call ActionScript classes that help the view with more defined and fewer responsibilities utility classes. Utility classes usually don’t have references to views. They could i.e. be formatters.</p>

<p>Personally I find Code Behind is indeed a nice and quick way to organize functionality. However, I’d argue that if you would move code from a MXML Script block into a Code Behind class, you’re just changing the location and potentially rough syntax of that code. After this “refactoring”, your code still lives in the same context.</p>

<p>In a middle and larger scale application i.e. using Cairngorm, I’d advocate extracting functionality from views into unit-testable model and utility classes. IMHO such classes are best created when they don’t contain any references to views and few responsibilities. They should be simple ActionScript classes without dependencies on other contexts such as view components.</p>

<p>I’m not saying you couldn’t unit-test Code Behind classes. It is like unit-testing Cairngorm View Helpers, people have done this and are doing it successfully. However, I just find it easier to unit-test and also reuse classes that contain defined functionality adhering to OOP rules. If you keep your functionality in view code, this functionality often has much more responsibilities to keep track of.</p>

<p>Once you're focusing on extracting the right functionality from your views and commands into unit testable utility classes and an application model deciding if you'd rather have Code Behind, View Helper or an MXML script block becomes less of an important decision to take. Once you've extracted functionality out of views, the view code left, isn't usually that big. Just converting this view code into a different syntax (Code Behind, View Helper or MXML script block) doesn't necessarily make it much better.</p>]]>
</content>
</entry>
<entry>
<title>Download Distortion Effects – From MAX 2006</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/11/download_distor.html" />
<modified>2009-01-25T16:39:39Z</modified>
<issued>2006-11-03T01:08:24Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.12418</id>
<created>2006-11-03T01:08:24Z</created>
<summary type="text/plain">For everyone who couldn’t attend my MAX presentation in Las Vegas, here is the presentation as PDF. Furthermore, I’ve released the complete source code for every effect shown. And here is the Flex 2.0.1 version. Behind the scenes, these effects...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Effects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>For everyone who couldn’t attend my MAX presentation in Las Vegas, <a href="http://weblogs.macromedia.com/auhlmann/archives/RI201W_TCE_Uhlmann.pdf">here</a> is the presentation as PDF. Furthermore, I’ve released the <a href="http://weblogs.macromedia.com/auhlmann/archives/DistortionEffects.zip">complete source code</a> for every effect shown.</p>

<p>And <a href="http://weblogs.macromedia.com/auhlmann/archives/DistortionEffects_Flex_2_0_1.zip">here</a> is the Flex 2.0.1 version.</p>

<p>Behind the scenes, these effects are using the DistortImage utility from the <a href="http://www.flashsandy.org/">open source 3D Engine Sandy</a>. Make sure you check out Sandy if you haven’t yet! The effects included are called Flip, CubeRotate, Push, Pop, Door and Gate. But instead of talking about them, just <a href="http://www.alex-uhlmann.de/flash/adobe/blog/distortionEffects/effectCube/">see them in action</a> for yourself:</p>

<p><strong>Distortion Effects</strong></p>

<p><a href="http://www.alex-uhlmann.de/flash/adobe/blog/distortionEffects/effectCube/">This sample application</a> lets you play with all effects available. You can also see different configurations, i.e. try enabling the blur checkbox.</p>

<p><img alt="FlipCubeBlur1.png" src="http://weblogs.macromedia.com/auhlmann/archives/FlipCubeBlur1.png" width="377" height="216" /></p>]]>
<![CDATA[<p>With the source code, you can use all the showcased effects in your own applications. They tie into the existing Flex 2 Effects Framework infrastructure, meaning you can use them in ActionScript, Transitions, hideEffect properties etc...like any other Flex 2 Effect. Here is one simple example on how it looks like using a hideEffect:</p>

<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:VBox 
	xmlns:mx="http://www.adobe.com/2006/mxml" 
	xmlns:sides="view.sides.*"
	xmlns:mxeffects="com.adobe.ac.mxeffects.*"&gt;
        
	&lt;mxeffects:CubeRotate 
		id="flipIn" 
		target="{ login }" siblings="{ [ registration ] }" 
		direction="RIGHT" duration="1000"/&gt;
	&lt;mxeffects:CubeRotate 
		id="flipBack" 
		target="{ registration }" siblings="{ [ login ] }" 
		direction="LEFT" duration="1000"/&gt;
        
	&lt;mx:ViewStack id="loginViewStack"&gt;
        
		&lt;sides:Login 
			id="login" 
			title="Login" 
			hideEffect="{ flipIn }" 
			change="loginViewStack.selectedChild = registration;"/&gt;
		&lt;sides:Registration 
			id="registration" 
			title="Registration" 			
			hideEffect="{ flipBack }" 
			change="loginViewStack.selectedChild = login;"/&gt;
	
	&lt;/mx:ViewStack&gt;
	
&lt;/mx:VBox&gt;
</pre>

<p>And here is how it looks like using States and Transitions:</p>

<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:Canvas 
	xmlns:mx="http://www.adobe.com/2006/mxml" 
	xmlns:sides="view.sides.*" 
	xmlns:mxeffects="com.adobe.ac.mxeffects.*"&gt;
	
	&lt;mx:states&gt;
		&lt;mx:State name="registrationState"&gt;
			&lt;mx:RemoveChild target="{ login }"/&gt;
			&lt;mx:AddChild&gt;
				&lt;sides:Registration 
					id="registration" title="Registration" 
					change="currentState = ''" /&gt;
			&lt;/mx:AddChild&gt;
		&lt;/mx:State&gt;
	&lt;/mx:states&gt;
	
	&lt;mx:transitions&gt;
		&lt;mx:Transition fromState="" toState="registrationState" 
			effect="{ flipFront }"/&gt;
		&lt;mx:Transition fromState="registrationState" toState="" 
			effect="{ flipBack }"/&gt;
	&lt;/mx:transitions&gt;
	
	&lt;mx:Sequence id="flipFront"&gt;		
		
		&lt;mxeffects:CubeRotate 
			target="{ login }" siblings="{ [ registration ] }" 
			direction="RIGHT"/&gt;
		
		&lt;mx:RemoveChildAction target="{ login }"/&gt;
		&lt;mx:AddChildAction target="{ registration }"/&gt;				
	&lt;/mx:Sequence&gt;
	
	&lt;mx:Sequence id="flipBack"&gt;		
	
		&lt;mxeffects:CubeRotate 
			target="{ registration }" siblings="{ [ login ] }" 
			direction="LEFT"/&gt;
			
		&lt;mx:RemoveChildAction target="{ registration }"/&gt;
		&lt;mx:AddChildAction target="{ login }"/&gt;				
	&lt;/mx:Sequence&gt;
	
	&lt;sides:Login id="login" title="Login" 
		change="currentState = 'registrationState';"/&gt;
	
&lt;/mx:Canvas&gt;
</pre>

<p>You can also create your own customized Flex Framework Effects using base and utility classes of the distortion effects. Make sure you check out the chapter 15 of <a href="http://download.macromedia.com/pub/documentation/en/flex/2/flex2_createextendcomponents.pdf">Creating and Extending Flex 2 Components</a> (flex.org > Documentation) for more information on Flex Effects customizations.</p>

<p><strong>Distortions</strong></p>

<p>Independently of effects, you can also use the source code to create your own distortions using the com.adobe.ac.mxeffects.Distortion. The API can be very simple i.e. like:</p>

<pre>
var distortion : Distortion = new Distortion( login );
distortion.push( 50, DistortionConstants.TOP );
</pre>

<p>For more customized distortions you can use the <a href="http://www.alex-uhlmann.de/flash/adobe/blog/distortionEffects/explorer/">distortion explorer</a>, which is also included in the download.</p>

<p>The Flex 2 Framework is free but still, you might not able to use it because you create extremely lightweight (filesize) content or/and developing with the Flash IDE (Flash Professional 9 ActionScript 3.0 Preview). Anyway, you can still make use of distortions with using com.adobe.ac.mxeffects.SimpleDistortion.</p>

<p><strong>Determining Filter Bounds at Runtime</strong></p>

<p>And independently of effects and distortions, you might want to use the com.adobe.ac.util.DisplayObjectBoundsUtil if you’re looking for how to determine the bounds (width and height) of a display object at runtime that might have filters applied. Check on SimpleDisplayObjectBoundsUtil if you can’t use the Flex framework.</p>

<p>For usage, just add the included DistortionEffects.swc into your project, check out the included sample applications and let me know how you get on with it!</p>

<p>UPDATED: I've published a blog entry to an updated version <a href="http://weblogs.macromedia.com/auhlmann/archives/2007/03/distortion_effe.cfm#more">here</a>. The source code and example links on this blog entry contain the updated version.<br />
</p>]]>
</content>
</entry>
<entry>
<title>Using Binding Securely</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/using_binding_s.html" />
<modified>2006-09-29T02:32:34Z</modified>
<issued>2006-09-28T11:58:59Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.12067</id>
<created>2006-09-28T11:58:59Z</created>
<summary type="text/plain">In my last post about the Cairngorm Dashboard example I’ve added a little functionality that allowed a view to react to a state change in the model in order to do something view related like invoking a popup or an...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Best Practice</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>In <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/cairngorm_sampl_3.cfm">my last post</a> about the Cairngorm Dashboard example I’ve added a little functionality that allowed a view to react to a state change in the model in order to do something view related like invoking a popup or an effect.</p>

<p>I’ve been using the binding approach and that made it very easy and flexible to do. But as I said in my last post, this can have one slight drawback you have to consider. In this post I’ll showcase the drawback and provide a solution to it via an extended version of <a href="http://weblogs.macromedia.com/paulw/">Paul’s</a> <a href="http://weblogs.macromedia.com/paulw/archives/2006/05/the_worlds_smal.cfm">Observe tag</a>.  Furthermore, this extended version of Observe makes it even easier to perform this kind of listening to the model.</p>]]>
<![CDATA[<p>Behind the scenes, binding uses <a href="http://livedocs.macromedia.com/flex/2/langref/flash/events/EventDispatcher.html">flash.events.EventDispatcher</a>. But binding gives you much more than just that. You can bind to properties even when their objects aren't initialized yet. You can also bind to XML data using E4X to specifically listen to certain areas of the XML. For more information on the features of binding make sure you read the Chapter 37 in Part 5 of the Flex 2 Developer’s Guide.</p>

<p>There are multiple ways to use binding. All of them require a source that defines what property you want to listen to and a destination that defines what shall be triggered once your source changes. <br />
You can either use the MXML curly braces syntax, function binding, the mx:Binding tag or define bindings in ActionScript.</p>

<p>Either way, you have to be careful in triggering application code in a destination of a binding, which we've done in previous examples of my Dashboard sample using either function binding to trigger a formatter or mx:Binding to invoke a view related method.<br />
Since the Binding feature hides us from many exceptions that would have been thrown using EventDispatcher, it cannot differentiate in certain situations when certain; to us important, exceptions are thrown in our application code that is triggered in the destination. Let's showcase this and throw one of these "certain" exceptions on purpose in our <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/cairngorm_sampl_3.cfm">latest Cairngorm Dashboard sample</a>. Let's throw one that I'm sure you've have seen before: The one and famous:</p>

<p><strong>ErrorID 1009: "Cannot access a property or method of a null object reference."</strong></p>

<p>Change the <code>createChargedMessage</code> setter to:</p>

<pre>
private function set createChargedMessage( value : Boolean ) : void
{
        var o1 : Object = {};
	o1.o2 = {};
	trace( "show o2 " + o1.o2 );	
	o1.o2 = null;
	o1.o2.foo = "bar"; //oops, o2 doesn't exist, an exception should be thrown.
	trace( "show foo " + o1.o2.foo );
	if( value ) Alert.show( "Thanks! Your bank account has been charged" );
}
</pre>

<p>Since this code is triggered as a destination of the mx:Binding tag, the runtime exception that should appear on </p>

<pre>
o1.o2 = null;
o1.o2.foo = "bar";
</pre>

<p>is swallowed by the binding code in the Flex framework. You will not see the usually expected runtime exception displayed via the Flash Debug Player. Instead, the following code like the <code>trace( "show foo " + o1.o2.foo );</code> will just not execute. </p>

<p>Note, that this will only happen with certain exceptions. It will only happen on the following exceptions:</p>

<ul>
<li>Error #1006: Call attempted on an object that is not a function.</li>
<li>Error #1009: null has no properties.</li>
<li>Error #1010: undefined has no properties.</li>
<li>Error #1055: - has no properties.</li>
<li>Error #1069: Property - not found on - and there is no default value</li>
</ul>

<p>For more information on these errors take a look at <a href="http://livedocs.macromedia.com/flex/2/langref/runtimeErrors.html">Run-Time Errors</a> of Adobe Livedocs.</p>

<p>Note also, that this will only happen when your application code in the destination executes in the same ActionScript block. This means if your exception throwing code executes in a different frame (as would usually be the case on a custom effect) you will see a runtime exception as expected.</p>

<p>However, if your application code does throw one of the swallowed exceptions in the same ActionScript block, there are ways so you can see this immediately.</p>

<p>You could use a special debug class in the Flex framework to help you see the error message. Use <br />
<code>mx.binding.BindingManager.debugBinding( &lt;your destination as a String&gt );</code></p>

<p>But in a production environment I'd recommend you use another more bullet-prove way of solving this problem. You can use the extended version of Paul’s Observe tag.</p>

<pre>
&lt;ac:Observe 
	source="{ stockTransaction.stockPurchase.isComplete }" 
	handler="{ createChargedMessage }"/&gt
</pre>

<p>Using Observe you can invoke a method instead of the setter.</p>

<pre>
private function createChargedMessage( value : Boolean ) : void
{
	if( value ) Alert.show( "Thanks! Your bank account has been charged" );
}
</pre>

<p>Try putting the code from above that will throw a runtime exception into the <code>createChargedMessage</code> method. Observe will make sure that a runtime exception is being thrown as expected.<br />
Internally, Observe wraps another global Error handler around your destination, saves the exception thrown and throws it in the next frame.</p>

<p>Furthermore this approach offers an additional feature for your convenience. If you want to listen to only a specific value of the source, you can use ObserveValue for this. In our use case of the <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/cairngorm_sampl_3.cfm">iteration 6 Cairngorm Dashboard</a> we just want to know when the isComplete property of our StockPurchase object is true.</p>

<pre>
&lt;ac:ObserveValue 
	id="observe" 
	source="{ stockTransaction.stockPurchase.isComplete }" 
	handler="{ createChargedMessage }" 
	value="{ true }"/&gt
</pre>

<pre>
private function createChargedMessage() : void
{
	Alert.show( "Thanks! Your bank account has been charged" );
}
</pre>

<p>I've mentioned above that this also applies to function bindings. In <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration6/srcview/source/com/adobe/cairngorm/samples/dashboard/view/StockMarketPod.mxml.html">StockMarketPod.mxml</a> of the <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/cairngorm_sampl_3.cfm">iteration 6 Cairngorm Dashboard sample application</a>, I've used the provided <code>Observe.execute</code> method in order to ensure a secure use of our function binding, which tirggers a custom formatter. </p>

<pre>
&lt;mx:Label text="{ observe.execute( statusFormatter.format, stockTransaction.status ) }"/&gt;
</pre>

<p>You can download the <a href="http://weblogs.macromedia.com/auhlmann/archives/ObserveUtility.zip">Observe and ObserveValue utility classes from here</a>.</p>

<p>Hope this helps!</p>]]>
</content>
</entry>
<entry>
<title>Cairngorm Sample – How Business Logic Can Manage Views Part IV</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/cairngorm_sampl_3.html" />
<modified>2006-09-29T05:49:27Z</modified>
<issued>2006-09-28T11:15:10Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.12066</id>
<created>2006-09-28T11:15:10Z</created>
<summary type="text/plain">In the last post about this topic, I’ve added some functionality and another use case to our stock quote application and showcased how a Cairngorm application could scale with focusing on creating model objects. In this post I’ll perform some...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Cairngorm</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>In the <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/07/cairngorm_sampl_2.cfm">last post about this topic</a>, I’ve added some functionality and another use case to our stock quote application and showcased how a Cairngorm application could scale with focusing on creating model objects. In this post I’ll perform some further refactorings to our model objects.</p>

<p>Furthermore, our customer wants us to show a pop-up as soon as a successful stock purchase is being made. I’ll cover how a state change in your model can transparently cause view related code (like creating a pop-up) to be executed.</p>]]>
<![CDATA[<p><strong>Iteration 6 - Refactorings</strong></p>

<p>In iteration 5 we had a statusMessage field in both model objects, <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration5/srcview/source/com/adobe/cairngorm/samples/dashboard/model/StockQuote.as.html">StockQuote</a> and <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration5/srcview/source/com/adobe/cairngorm/samples/dashboard/model/StockPurchase.as.html">StockPurchase</a>. Two separate text input fields have listened to these properties. Now, let’s only have one status message for both model objects. This i.e. could bring us to the idea of creating another object that encapsulates StockQuote and StockPurchase. Let’s call it StockTransaction:</p>

<pre>
package com.adobe.cairngorm.samples.dashboard.model
{
	public class StockTransaction
	{
		[Bindable]
		public var stockQuote : StockQuote;		
		[Bindable]
		public var stockPurchase : StockPurchase;		
		[Bindable]
		public var status : int;
		
		public function StockTransaction()
		{
			stockQuote = new StockQuote();
			stockPurchase = new StockPurchase( stockQuote );
		}
	}
}
</pre>

<p>Note that in the above, I’ve changed the previous statusMessage property; which was typed as a String, to a status property; which is typed as an int. I’ve done that so our model objects can only be concerned with a status of our use case and not with the presentation of this status. I think the presentation of the status is something that our views should be responsible for.</p>

<p>Our model objects can contain the different status options they can be in. i.e. our new <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration6/srcview/source/com/adobe/cairngorm/samples/dashboard/model/StockQuote.as.html">StockQuote</a> object can have an ERROR and a SUCCESS status, showing that the StockQuote retrieval was either successful or not. So, we can define the states with two values.</p>

<pre>
public static const ERROR : int = 1;
public static const SUCCESS : int = 0;
</pre>

<p>In our new <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration6/srcview/source/com/adobe/cairngorm/samples/dashboard/command/GetStockQuoteCommand.as.html">GetStockQuoteCommand</a> we can decide in what state the StockQuote object is currently in. Here’s a snippet of it:</p>

<pre>
public function onResult( event : * = null ) : void
{
	//for demo purpose: event would normally be an event object of remote service result.
	stockTransaction.stockQuote.lastStockQuote = event as Number;			
	stockTransaction.stockQuote.isPending = false;
	stockTransaction.status = StockQuote.SUCCESS;
}
		
public function onFault( event : * = null ) : void
{
	stockTransaction.stockQuote.lastStockQuote = NaN;
	stockTransaction.status = StockQuote.ERROR;
	stockTransaction.stockQuote.isPending = false;	   	
}
</pre>

<p>There are various ways to achieve a similar separation of concerns. In this application however, I'll let the <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration6/srcview/source/com/adobe/cairngorm/samples/dashboard/view/StockMarketPod.mxml.html">StockMarketPod.mxml</a> view listen to the value of status and depending on the status value, StockMarketPod will display a String, which is defined on this view. StockMarketPod uses a helper class called <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration6/srcview/source/com/adobe/cairngorm/samples/dashboard/view/StatusMessageFormatter.as.html">StatusMessageFormatter</a> that translates the status property into the correct String needed by the view. This helper class is initialized like this:</p>

<pre>
&lt;view:StatusMessageFormatter 
	id="statusFormatter" 
	statusMessages="{ [ '', 'Quote retrieval error.', 'Purchase error.', 'Purchase succesfull.' ] }"/&gt;	
</pre>

<p>I listen to the status via a function binding on the status property. For more information on this you can take a look into the full source code for this application at the end of this post.</p>

<p>Flex 2 make it easy to perform refactorings like this. This is very important since refactorings of your model objects can occur all the time and most often you rarely get it right the first time around. ;)</p>

<p><strong>Iteration 6 - Invoking View Related Methods</strong></p>

<p>As said in the beginning of this post, our customer wants us to alert the user via popup when a stock purchase request has successfully been made. Let’s think of creating a simple Alert window (mx.controls.Alert). When the onResult handler of the PurchaseStockCommand is invoked we know a stock purchase has been completed. </p>

<p>I think of creating an Alert control as something only views should be concerned about. It’s like creating other view components, managing states of view components or effects. I think only views should be responsible. Usually we bind UI controls to properties of our model objects. But for creating an Alert control, there’s no UI component where we can bind to. How do we best let a view invoke a view related method after a certain state change in our model occurred?</p>

<p>I basically see two ways to do this from a model. We could manipulate a model object so it dispatches an EventDispatcher event that the view can listen to. We could also just mark properties of our model as Bindable and let our views subscribe to either a custom event name that you have defined in our Bindable metadata (with <code>[Bindable(event="customEventName")]</code>), or to the default "propertyChange" event. Using the propertyChange event your view's event handler method would have to differentiate what property changed. You can do that with the passed in mx.events.PropertyChangeEvent object. Listening to a custom event name defined in the Bindable metadata, we have to dispatch the event manually using dispatchEvent.</p>

<p>I see two drawbacks using this approach. First of all, it’s more code to write and most importantly, to read. This is because your views need to subscribe manually to events and define event handlers. It might also affect your models since some of them might need extra EventDispatcher functionality. Secondly, we need to make sure that our model objects exist when the view is subscribing to the event.</p>

<p>The latter is something binding gives us for free. We can bind to a state change of a model even if the model isn’t initialized at the time of subscription. Furthermore, using the binding approach is just quicker to do in many cases. </p>

<p>Following the binding approach, we can bind to a property of our model objects and invoke a method in our views with using the mx:Binding tag. </p>

<p>This could look like the below:</p>

<pre>
private function set createChargedMessage( value : Boolean ) : void
{
	if( value ) Alert.show( "Thanks! Your bank account has been charged" );
}
</pre>

<pre>
&lt;mx:Binding 
	source="stockTransaction.stockPurchase.isComplete" 
	destination="createChargedMessage"/&gt	
</pre>

<p>Now, instead of using mx:Binding I recommend that you use an extended version of the Observe tag that <a href="http://weblogs.macromedia.com/paulw/">Paul Williams</a> originally <a href="http://weblogs.macromedia.com/paulw/archives/2006/05/the_worlds_smal.cfm">blogged</a>. </p>

<p>This can make your code more secure, and furthermore it does also give you a slightly easier API to solve the problem here. We only need to listen to the "true" value of the isComplete Boolean. Therefore, we tell our new utility exactly this.</p>

<pre>
&lt;ac:ObserveValue 
	id="observe" 
	source="{ stockTransaction.stockPurchase.isComplete }" 
	handler="{ createChargedMessage }" 
	value="{ true }"/&gt
</pre>

<p>The createChargedMessage will be reduced to this:</p>

<pre>
private function createChargedMessage() : void
{
	Alert.show( "Thanks! Your bank account has been charged" );
}
</pre>

<p>For more information on why I’ve introduced this utility class, please read the follow up post on this topic, <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/using_binding_s.cfm">"Using Binding Securely"</a>.</p>

<p><strong>Summary</strong></p>

<p>What have we done here?</p>

<p>We needed our view to invoke a view related method based on some state change in our model. First, we’ve changed the state in the model with invoking a Command. The Command located our model object via ModelLocator and changed the state of this model object via its API. Because our view subscribed to this specific state change (via binding in our case), it could react to it with invoking a method. Since it was using mx:Binding, we didn’t need any extra ActionScript to setup the binding, neither did we need a MXML component that would accept a return value (which we didn’t have since we were calling a popup).</p>

<p>As I’ve noted above, there’s also one little drawback on how we use the binding approach here.</p>

<p>For more information on the drawback and a solution to it with an additional feature please read the next post, <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/using_binding_s.cfm">"Using Binding Securely"</a></p>

<p>As after every post in this series, you can <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration6/DashboardIteration6.html">view the application and download the source code</a> of it via right mouse click > View Source.</p>]]>
</content>
</entry>
<entry>
<title>MAX 2006: Leveraging Flex 2 and Flash Player 9 for Truly Cinematic Experiences</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/09/max_2006_levera.html" />
<modified>2006-09-08T10:58:53Z</modified>
<issued>2006-09-08T10:35:56Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.11896</id>
<created>2006-09-08T10:35:56Z</created>
<summary type="text/plain">As MAX 2006 in Las Vegas is coming closer and it’s shaping up to be a fascinating conference. I’m talking about Leveraging Flex 2 and Flash Player 9 for Truly Cinematic Experiences and I’d like to give you more information...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Effects</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>As MAX 2006 in Las Vegas is coming closer and it’s shaping up to be a <a href="http://www.adobe.com/events/max/agenda/by_track.html">fascinating conference</a>. I’m talking about</p>

<p><a href="http://www.adobe.com/events/max/sessions/ri210w.html">Leveraging Flex 2 and Flash Player 9 for Truly Cinematic Experiences</a></p>

<p>and I’d like to give you more information where this will be about, in hope you consider joining my session!</p>

<p>I’ll talk about how cinematic effects can dramatically improve the user experience of a Rich Internet Application and can contribute significantly to the success of how your RIA will translate the experience that your costumer wants to deliver. </p>

<p>You will see new types of effects and learn best practices toward their use and creation.</p>]]>
<![CDATA[<p><strong>New Flex Effects Leveraging Flex 2 Features</strong></p>

<p>I’ll showcase a variety of different effects but most importantly I'll showcase a new type of cinematic effects, leveraging the performance improvements, the new bitmap manipulation features and the new Effects Framework in Flex 2. You'll be given ideas and complete source code for these new type of effects and will be able to create your own customized effects based on the principles demonstrated.</p>

<p>One of these effects is a flip effect. I’ve a little teaser for you here:</p>

<p><a href="http://weblogs.macromedia.com/auhlmann/max2006/simpleflip/FlipExample.html">See the Flip effect</a></p>

<p>How this is done, how you can use it in your own work and how all the other effects look like…stay tuned for MAX 2006!</p>

<p><strong>Future of AnimationPackage</strong></p>

<p>Some of you might know that I’ve developed <a href="http://www.alex-uhlmann.de/flash/animationpackage/">AnimationPackage</a>, an ActionScript 2 library for Flash and Flex 1.x developers. I’ll outline how I see the future of this framework and how I see it fitting alongside the Flex 2 effects framework.</p>

<p>See you soon, on the <br />
25. October, Wednesday, 1:45 p.m<br />
and the <br />
26. October, Thursday, 3:00 p.m. <br />
in Las Vegas!</p>

<p>I'm excited!</p>]]>
</content>
</entry>
<entry>
<title>Cairngorm Sample – How Business Logic Can Manage Views Part III</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/07/cairngorm_sampl_2.html" />
<modified>2006-07-20T16:38:20Z</modified>
<issued>2006-07-20T11:47:58Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.11500</id>
<created>2006-07-20T11:47:58Z</created>
<summary type="text/plain">The goal of this series is to demonstrate how you can manage views with investing in your client side business logic. The previous posts (part 1, part 2) were primarily about the infrastructure of a very simple single and multiple...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Cairngorm</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>The goal of this series is to demonstrate how you can manage views with investing in your client side business logic. </p>

<p>The previous posts (<a href="http://weblogs.macromedia.com/auhlmann/archives/2006/06/cairngorm_sampl.cfm">part 1</a>, <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/06/cairngorm_sampl_1.cfm">part 2</a>) were primarily about the infrastructure of a very simple <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration2/DashboardIteration2.html">single</a> and <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration3/DashboardIteration3.html">multiple</a> view dashboard application. This and the following posts will add further functionality to the application with the indent to demonstrate how your model objects become a focus point of your application.</p>

<p>In particular, we'll add validation logic, formatting logic and an additional use case.</p>]]>
<![CDATA[<p><strong>Iteration 4 – Adding Functionality</strong></p>

<p>Let's go back to our <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration2/DashboardIteration2.html">single view dashboard</a> and let's first make this application a bit more realistic with simulating a delay for the dummy remote service that is invoked after the user presses the "Get Quote" button. I'll just add a <a href="http://livedocs.macromedia.com/flex/2/langref/flash/utils/package.html#setTimeout()">flash.utils.setTimeout</a> method in our iteration 2 delegate (<a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration2/srcview/source/com/adobe/cairngorm/samples/dashboard/business/StockMarketDelegate.as.html">StockMarketDelegate.as</a>) to simulate a delay.</p>

<p>Usually, while a remote service is being processed, the UI is supposed to react to it with i.e. displaying a progress or disabling certain UI components to let the user know that further requests cannot be dispatched. In our use case we'd like to disable the "Get Quote" button while a remote service call is being processed. We can achieve this easily with adding a property to our representing model object from iteration 2 <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration2/srcview/source/com/adobe/cairngorm/samples/dashboard/model/StockQuote.as.html">StockQuote</a>. Let's call it isPending and make it a Boolean where our view can bind to.</p>

<pre>
[Bindable]
public var isPending : Boolean;
</pre>

<p><strong>Adding Validation Logic</strong></p>

<p>Let's add a validation of our stock quote with inspecting the actual stock quote value. We can easily use the <a href="http://livedocs.macromedia.com/flex/2/langref/mx/validators/StringValidator.html">mx.validators.StringValidator</a> of the Flex Framework for this type of work.</p>

<p>In our application we need both parameters of validations (isPending and the result of StringValidator) to pass in order to let the UI allow a remote service request. Our model object could have an isValid property, which combines these two parameters of validation. I compute isValid with the following method.</p>

<pre>
private function validate() : void
{
	isValid = ( isSymbolValid && !isPending );
}
</pre>

<p>isSymbolValid is a property, which will be the result of our StringValidator.</p>

<p>We could add the mx:StringValidator tag into the StockMarketPod.mxml and have it calling the StockQuote model object on its "valid" and "invalid" events.</p>

<pre>
&lt;mx:StringValidator 
	minLength="2" triggerEvent="change" 
	source="{ symbolTextInput }" property="text"
	valid="stockQuote.validateSymbol( true );" 
	invalid="stockQuote.validateSymbol( false );"/&gt;
</pre>

<p>To call a model object directly from the view isn't the clearest form of MVC since views should only dispatch events, which are handled by your controller. But for this example I find it good enough to have a method be called directly from the view. In my humble opinion this use case doesn't justify a "round trip" to the model object just yet. Think: "The simplest thing that could possibly work".</p>

<p><strong>Adding Formatting Logic</strong></p>

<p>This is easy. We want to have our stock quote result being formatted with a currency formatter. You could define the formatter in StockMarketPod.mxml with</p>

<pre>
&lt;mx:CurrencyFormatter 
	id="standardEuroFormatter"  
	currencySymbol="€" precision="2"/&gt;
</pre>

<p>and have it formatting with a method binding</p>

<pre>
&lt;mx:Label text="{ standardEuroFormatter.format( stockQuote.lastStockQuote ) }"/&gt;
</pre>

<p>Now, let's have a complete look into our <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration4/srcview/source/com/adobe/cairngorm/samples/dashboard/model/StockQuote.as.html">StockQuote</a> model object.</p>

<pre>
package com.adobe.cairngorm.samples.dashboard.model
{
	public class StockQuote
	{
		[Bindable]
		public var lastStockQuote : Number;
		[Bindable]
		public var isValid : Boolean;
		[Bindable]
		public var statusMessage : String;
				
		private var _isPending : Boolean;
		private var isSymbolValid : Boolean;
                
		[Bindable]
		public function get isPending() : Boolean
		{
			return _isPending;
		}
		
		public function set isPending( value : Boolean ) : void
		{
			_isPending = value;
			validate();
		}
			
		public function validateSymbol( isValid : Boolean ) : void
		{
			isSymbolValid = isValid;
			validate();
		}
		
		private function validate() : void
		{
			isValid = ( isSymbolValid && !isPending );
		}		
	}
}
</pre>

<p>The new isPending state is being manipulated by the <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration4/srcview/source/com/adobe/cairngorm/samples/dashboard/command/GetStockQuoteCommand.as.html">GetStockQuoteCommand</a>.</p>

<pre>
private var model : ModelLocator = ModelLocator.getInstance();
private var stockQuote : StockQuote = model.stockQuote;
	 	
public function execute( event : CairngormEvent ) : void
{
	stockQuote.isPending = true;
	     	
	var stockQuoteEvent : GetStockQuoteEvent = GetStockQuoteEvent( event );	      
	var symbol : String = stockQuoteEvent.symbol;
	var delegate : StockMarketDelegate = new StockMarketDelegate( this );
	delegate.getQuoteForSymbol( symbol );    
}
		
public function onResult( event : * = null ) : void
{
	//for demo purpose: event would normally be an event object of remote service result.			
	stockQuote.lastStockQuote = event as Number;			
	stockQuote.isPending = false;
	stockQuote.statusMessage = "";
}
		
public function onFault( event : * = null ) : void
{
	stockQuote.lastStockQuote = NaN;
	stockQuote.statusMessage = "Quote retrieval error.";
	stockQuote.isPending = false;
}
</pre>

<p>And let's finally look into our view <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration4/srcview/source/com/adobe/cairngorm/samples/dashboard/view/StockMarketPod.mxml.html">StockMarketPod.mxml</a></p>

<pre>
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:Panel 
	xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:util="com.adobe.cairngorm.samples.dashboard.util.*"&gt;
        
	&lt;mx:Script&gt;
		&lt;![CDATA[
			import com.adobe.cairngorm.control.CairngormEventDispatcher;
			import com.adobe.cairngorm.samples.dashboard.model.StockQuote;
			import com.adobe.cairngorm.samples.dashboard.events.GetStockQuoteEvent;	
			
			[Bindable]
			public var stockQuote : StockQuote;
			
			private function getQuoteForSymbol() : void
			{
				var event : GetStockQuoteEvent = new GetStockQuoteEvent( symbolTextInput.text );
				CairngormEventDispatcher.getInstance().dispatchEvent( event );
			}
		]]&gt;
	&lt;/mx:Script&gt;
	
	&lt;mx:CurrencyFormatter 
                id="standardEuroFormatter"  
		currencySymbol="€" precision="2"/&gt;
		
	&lt;mx:StringValidator 
		minLength="2" triggerEvent="change" 
		source="{ symbolTextInput }" property="text"
		valid="stockQuote.validateSymbol( true );" 
		invalid="stockQuote.validateSymbol( false );"/&gt;
	
	&lt;mx:Form&gt;
	
		&lt;mx:FormItem label="Symbol"&gt;
			&lt;mx:TextInput 
				id="symbolTextInput"/&gt;
			&lt;mx:Button 
				label="Get Quote" 
				enabled="{ stockQuote.isValid }" 
				click="getQuoteForSymbol();"/&gt;
		&lt;/mx:FormItem&gt;
				
		&lt;mx:FormItem label="Price Quote"&gt;
			&lt;mx:Label text="{ standardEuroFormatter.format( stockQuote.lastStockQuote ) }"/&gt;
			&lt;mx:Label text="{ stockQuote.statusMessage }"/&gt;
		&lt;/mx:FormItem&gt;
		
	&lt;/mx:Form&gt;	
&lt;/mx:Panel&gt;
</pre>

<p><br />
Note, that this version of StockMarketPod.mxml doesn't have a reference to ModelLocator anymore. Instead, the model objects, which are needed, are passed into StockMarketPod.mxml. </p>

<pre>
&lt;mx:Script&gt;
	&lt;![CDATA[
		import com.adobe.cairngorm.samples.dashboard.model.ModelLocator;
		import com.adobe.cairngorm.samples.dashboard.model.StockQuote;
									
		[Bindable]
		private var model : ModelLocator = ModelLocator.getInstance();
		[Bindable]
		private var stockQuote : StockQuote = model.stockQuote;	
	]]&gt;
&lt;/mx:Script&gt;
 
&lt;view:StockMarketPod 
	stockQuote="{ stockQuote }" 
	title="Stockmarket Pod"/&gt;
</pre>

<p>I find it beneficial to give view components only the information they need instead of global access to all your business logic through a reference of your ModelLocator. Furthermore, this makes view components more reusable across projects. </p>

<p>Optionally; to further increase view reusability, we could also replace CairngormEventDispatcher calls inside StockMarketPod.mxml with view events dispatched via EventDispatcher. We would handle these events outside the view component that we want to make reusable across applications and dispatch the Cairngorm event using CairngormEventDispatcher in order to reach application specific Cairngorm commands.</p>

<p><a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration4/DashboardIteration4.html">Download and "view source" the complete iteration 4 example.</a></p>

<p><strong>Iteration 5 – Adding a Use Case</strong></p>

<p>Let's pretend our customer now wants us to also purchase stocks after a stock quote has been retrieved. We are supposed to add another text input field with a quantity field that defines how many stocks the user would want to buy. Furthermore, we would need a purchase button. The purchase button must only be enabled when the user is allowed purchase a stock quote. This is the case when:</p>

<ul>
<li>the quantity field contains a valid value.</li>
<li>another stock purchase request is not pending.</li>
<li>a stock quote has been successfully retrieved.</li>
</ul>

<p>We could use another model object responsible for managing all this. Let's call it StockPurchase. StockPurchase can have a very similar structure than StockQuote. But the third bullet point requires StockPurchase to know about StockQuote's state. Only if StockQuote has been completed, StockPurchase's validation can pass completely. There are various ways to let StockPurchase know about StockQuote's state. For this example I just pass a reference of StockQuote to the constructor of StockPurchase. I'll do that inside an initialize method (here in <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration5/srcview/source/com/adobe/cairngorm/samples/dashboard/model/ModelLocator.as.html">ModelLocator</a>). This is being called at start up.</p>

<pre>
private function initialize() : void
{
	stockQuote = new StockQuote();
	stockPurchase = new StockPurchase( stockQuote );   		
}
</pre>

<p><a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration5/srcview/source/com/adobe/cairngorm/samples/dashboard/model/StockPurchase.as.html">Here</a> is the full source code of StockPurchase.</p>

<p>And <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration5/srcview/source/com/adobe/cairngorm/samples/dashboard/view/StockMarketPod.mxml.html">here</a> are the additions to StockMarketPod.mxml including the additional validator and formatter.</p>

<p>A new <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration5/srcview/source/com/adobe/cairngorm/samples/dashboard/command/PurchaseStockCommand.as.html">PurchaseStockCommand</a> finally sends the remote purchase request, handles the response and manipulates the client side model objects accordingly. Our views listen to model object events through bindings and translate the model data according to view related rules. This translation process could be done using view helpers like the mx:CurrencyFormatter used in this sample.</p>

<p><a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration5/DashboardIteration5.html">Download and "view source" the complete iteration 5 example.</a></p>

<p>I hope you've enjoyed my dashboard iterations so far. The most important point I wanted to bring across is how valuable I think it is to think about our model objects and try to extract much functionality out of our views. Going forward this way, I find it's much easier to build unit-testable, flexible and scalable Rich Internet Applications.</p>

<p>In the next iteration I'll cover some additional refactorings on the view and model objects and how state changes in the model can cause view related methods to be executed.</p>]]>
</content>
</entry>
<entry>
<title>Cairngorm 2 (for Flex 2) – Simple Sample Applications</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/07/cairngorm_2_for_1.html" />
<modified>2007-06-17T11:26:18Z</modified>
<issued>2006-07-05T16:39:01Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.11353</id>
<created>2006-07-05T16:39:01Z</created>
<summary type="text/plain">UPDATE: The Login example has been updated by Neil Webb to Cairngorm 2.2. Check out his series of articles explaining Cairngorm using the Login example. I&apos;d like to give you early access to a new version of the CairngormLogin sample,...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Cairngorm</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>UPDATE: The Login example has been updated by <a href="http://nwebb.co.uk/blog/">Neil Webb</a> to Cairngorm 2.2. Check out <a href="http://nwebb.co.uk/blog/?p=58">his series of articles</a> explaining Cairngorm using the Login example. </p>

<p>I'd like to give you early access to a new version of the <a href="http://www.alex-uhlmann.de/flash/adobe/blog/cairngormlogin/CairngormLogin.html">CairngormLogin sample</a>, which we'll ultimately make available on Adobe Labs. We’ve been releasing this very simple example application in earlier versions of Cairngorm alongside the framework code. Intention is to showcase how to get a simple Cairngorm application running. Furthermore, I’ve also upgraded my dashboard samples, which I’ve shown in <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/06/cairngorm_sampl_1.cfm">previous posts</a>.</p>]]>
<![CDATA[<p>I’ve done some little additions to the CairngormLogin sample that hopefully show a little more closeness to a real world Cairngorm application. There’s now a model object Login, which encapsulates login related states of the application. This object also contains a pending state, which a LoginPanel view listens to in order to prevent multiple login requests being fired before a running request has been returned. Also, there’s a delay in the delegate to simulate a remote service response. The code needed to call a remote service via RemoteObject is commented.</p>

<p>I’ve also updated the Dashboard examples to work with the latest Cairngorm release. Expect some further updates that actually add some real functionality to this in future.</p>

<p>see and download (right click and view source) the samples here:<br />
<ul><br />
<li><a href="http://www.alex-uhlmann.de/flash/adobe/blog/cairngormlogin/CairngormLogin.html">CairngormLogin sample</a></li><br />
<li><a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration1/DashboardIteration1.html">Dashboard sample iteration 1</a></li><br />
<li><a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration2/DashboardIteration2.html">Dashboard sample iteration 2</a></li><br />
<li><a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration3/DashboardIteration3.html">Dashboard sample iteration 3</a></li><br />
</ul></p>

<p>As <a href="http://weblogs.macromedia.com/swebster/">Steven Webster</a> mentioned previously, expect more examples from us coming up soon and let us know when you’ve examples to show. I think the more the better!</p>]]>
</content>
</entry>
<entry>
<title>Cairngorm 2 (for Flex 2) – Overview and Migration Path</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/07/cairngorm_2_for.html" />
<modified>2006-07-02T04:11:06Z</modified>
<issued>2006-07-02T03:47:57Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.11341</id>
<created>2006-07-02T03:47:57Z</created>
<summary type="text/plain">Earlier this week Cairngorm for Flex 2 has been released. There have been a number of changes compared to Cairngorm for Flex Beta 3. This post intents to explain some of what’s changed, why it changed and how you can...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Cairngorm</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>Earlier this week <a href="http://www.adobe.com/go/cairngorm">Cairngorm for Flex 2</a> <a href="http://weblogs.macromedia.com/swebster/archives/2006/06/cairngorm_2_for_2.cfm">has been released</a>. There have been a number of changes compared to Cairngorm for Flex Beta 3. This post intents to explain some of what’s changed, why it changed and how you can handle the changes for migrating your Cairngorm applications to the newest version. Sorry for the delay of this post, but as you might know, there’s a fantastic soccer World Cup in Germany going on these days. ;)</p>]]>
<![CDATA[<p><strong>1. Responder interface now optional and typeless.</strong></p>

<p>The signature of Responder has changed to an optional typeless (wildcard type '*') from the mx.rpc.events.ResultEvent and mx.rpc.events.FaultEvent signatures. Here are three reasons for this:</p>

<ul>
<li>You can now handle RemoteService, WebService, RemoteObject and non Flex framework remoting responses.</li>

<p><li>You can now more easily perform spikes (prototypes) to simulate a server side response. Just place stub data into the delegate and return that to the onResult handler of your Command. Since it’s optional, you don’t have to return any data to the Command.</li></p>

<p><li>If you unit test your Commands, this signature might also be handy.</li><br />
</ul></p>

<p><strong>2. Minor improvements</strong></p>

<p>There have been a number of minor improvements i.e. Cairngorm now prevents to add an already registered Command, the ViewHelper adds and removes itself from the ViewLocator once added or removed from the display list and other minor code refactorings have been performed as well.</p>

<p><strong>3. New Cairngorm Event Dispatcher</strong></p>

<p>This is the most significant change. For Cairngorm Flex 1 users this is familiar as it basically is EventBroadcaster with a more “Flex 2 EventDispatcher-like” syntax.</p>

<p>Here are the corresponding release notes:</p>

<blockquote>In the beta releases of Cairngorm for Flex 2, we departed from the Cairngorm 0.99 approach of dispatching events, and used the new built-in dispatchEvent method with bubbling available on Flex components. However, since bubbling is only available on the display list we had to listen to a top level child on the display list for all events, which we decided to be mx.core.Application.application. In cases where a view reference on the display list below mx.core.Application.application is not available, users had to obtain mx.core.Application.application directly in order to dispatch a Cairngorm event. This was often the case in for example pop-ups and other ActionScript classes without the appropiate view reference. Our experience within Adobe Consulting in delivering Flex 2 projects, coupled with community feedback, has encouraged us to revert to an architecture more like the original Cairngorm 0.99 architecture using EventBroadcaster. </blockquote>

<p>This is indented to encourage developers to have a clear separation of Cairngorm events and application events. The new CairngormEventDispatcher offers exactly this, since only event objects of type CairngormEvent can be dispatched and handled. Furthermore, CairngormEvent has the typeless data property for lazy people. ;) For more information about CairngormEventDispatcher, check out the ASDocs, temporarily available through <a href="http://weblogs.macromedia.com/amcleod/archives/2006/06/cairngorm_2_-_a.cfm">Alistair McLeod’s blog</a>.</p>

<p><strong>Migrating your Cairngorm Application.</strong></p>

<p>The Flex 2 compiler helps you most with migrating your application. For example it will tell you that the new Responder interface might not be compatible to your pre Cairngorm for Flex 2 application.</p>

<p>However, for larger applications a migration of the event dispatching system from legacy Cairngorm Flex beta Application.application event dispatching to the new event dispatching system using CairngormEventDispatcher could be a bit trickier to accomplish. </p>

<p>The reason is that there could be Cairngorm events that trigger and modify various things while they bubble up the display list till they arrive to the root of the display list and the FrontController. If you would just replace the dispatchEvent calls from the view with CairngormEventDispatcher calls, code that relies on bubbling of events will break. Therefore; in larger applications, this migration should probably not be done in one step.</p>

<p>I've created a little migration Front Controller, which can use both techniques simultaneously, so developers can replace this event dispatching code carefully step by step. Here is a potential migration path that you could perform:</p>

<ul>
<li>Delete all legacy Cairngorm framework code with the updated framework. Since it’s a package change, Flex Builder will make it easy for you to spot the places in the application that have to be changed due to Cairngorm 2.</li>

<p><li>Now, here’s the ugly part: In order to make this migration work, you’ve got to temporarily change a Cairngorm source file. Open com.adobe.cairngorm.control.CairngormEvent and set the default value of the bubbles property to true. Make sure you reverse this change after your migration. Or better: Use the Cairngorm framework ActionScript source files while you are in a migration period and replace all Cairngorm framework source files with the Cairngorm SWC file that accompanies the latest release of Cairngorm.</li></p>

<p><li>Let your application FrontController extend com.adobe.cairngorm.control.MigrationFrontController instead of com.adobe.cairngorm.control.FrontController.</li><br />
</ul></p>

<p>When you now run the application, you’ll receive logging statements if the deprecated cairngorm event dispatching call is invoked. This logging statement can help you to locate the event and help you to make a decision if it can be replaced without side effects. </p>

<p>using trace</p>

<pre>
---------------------------------------------------------------------------
 MigrationFrontController.handleDeprecated: Deprecated event dispatching used with:
			event object: com.adobe.cairngorm.samples.dashboard.events::GetStockQuoteEvent
			event.type: EVENT_GET_STOCK_QUOTE
			event.target: Dashboard0.StockMarketDashboard5._StockMarketPod1
			event source: com.adobe.cairngorm.samples.dashboard.view::StockMarketPod
			event.currentTarget: Dashboard0
</pre>

<p>or using mx.logging:</p>

<pre>
10:27:59.760 [INFO] com.adobe.cairngorm.samples.dashboard.control.DashboardController 
---------------------------------------------------------------------------
			MigrationFrontController.handleDeprecated: Deprecated event dispatching used with:
			event object: com.adobe.cairngorm.samples.dashboard.events::GetStockQuoteEvent
			event.type: EVENT_GET_STOCK_QUOTE
			event.target: Dashboard0.StockMarketDashboard5._StockMarketPod1
			event source: com.adobe.cairngorm.samples.dashboard.view::StockMarketPod
			event.currentTarget: Dashboard0

</pre>

<p><br />
<a href="http://weblogs.macromedia.com/auhlmann/archives/cairngorm2flex2/MigrationFrontController.zip">Download MigrationFrontController here.</a></p>]]>
</content>
</entry>
<entry>
<title>Cairngorm Sample – How Business Logic Can Manage Views Part II</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/06/cairngorm_sampl_1.html" />
<modified>2006-06-18T16:55:59Z</modified>
<issued>2006-06-18T16:21:07Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.11202</id>
<created>2006-06-18T16:21:07Z</created>
<summary type="text/plain">In the last post I’ve introduced you to the stock market dashboard sample application and how you can create business logic to manage your view. In this post and example, I’ll apply another use case to the sample application. With...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Cairngorm</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>In the <a href="http://weblogs.macromedia.com/auhlmann/archives/2006/06/cairngorm_sampl.cfm">last post</a> I’ve introduced you to the stock market dashboard sample application and how you can create business logic to manage your view. In this post and <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration3/DashboardIteration3.html">example</a>, I’ll apply another use case to the sample application. With adding multiple pods to the stock market dashboard, the user can request price quotes independently. Each pod has its own stock market data. I’ll cover how your business logic can be adjusted to manage each view. I’ll also touch on how stateless Commands can help making this application easier.</p>]]>
<![CDATA[<p><strong>Iteration 3 – Creating business logic that manages multiple views</strong></p>

<p>Often, I find use cases where many views of a same type share common functionality. Each view can be represented by a model object. The view can request the appropriate model object from a manager object at start up. For example the StockMarketDashboard.mxml would look like this with additional pods:</p>

<pre>
&lt;view:StockMarketPod 
	quoteId="quote1" 
	title="Stockmarket first pod"/&gt;
&lt;view:StockMarketPod 
	quoteId="quote2" 
	title="Stockmarket second pod"/&gt;
&lt;view:StockMarketPod 
	quoteId="quote3" 
	title="Stockmarket third pod"/&gt;
&lt;view:StockMarketPod 
	quoteId="quote4" 
	title="Stockmarket fourth pod"/&gt;
</pre>

<p>Notice that the view needs to send some form of unique identifier to the manager. We add this unique identifier to our StockQuote class. </p>

<pre>
package org.nevis.cairngorm.samples.dashboard.model
{
	public class StockQuote
	{
		[Bindable]
		public var lastStockQuote : Number;
		[Bindable]
		public var stockQuoteError : String;		
	}
}
</pre>

<p>The manager object StockQuoteManager, is declared at initialization on the ModelLocator instance. But how does this manager object look like?</p>

<p>Usually, I implement it with a hash map that is keyed by the view’s unique identifier. In the constructor we can initialize the hash map. In Flex 1.x we would have used a generic Object to create a hash map. In Flex 2, I like to use flash.utils.Dictionary, which more clearly shows the indent of the code.</p>

<pre>
public function StockQuoteManager() 
{
	stockQuotes = new Dictionary();
}
</pre>

<p>The getStockQuote method either creates or returns a specific StockQuote object based on the view’s unique identifier quoteId.</p>

<pre>
public function getStockQuote( quoteId : String ) : StockQuote
{
	var key : String = quoteId;
	if( stockQuotes[ key ] == null )
	{
		var stockQuote : StockQuote = new StockQuote();
		stockQuotes[ key ] = stockQuote;
	}
	return StockQuote( stockQuotes[ key ] );
}
</pre>

<p>The StockMarketPod.mxml almost looks identical to the old version of iteration 2, which refactored ModelLocator properties to the StockQuote model object. We just need to send the unique identifier to the Command, since the Command itself needs to retrieve a StockQuote object from the manager object. So the GetStockQuoteEvent class gets another quoteId property.</p>

<p>In GetStockQuoteCommand we need to store the unique identifier as an instance property since the command needs to retrieve and update the correct StockQuote object in an onResult or onFault handler.</p>

<pre>
private var model : ModelLocator = ModelLocator.getInstance();
private var quoteId : String;
	 	
public function execute( event : CairngormEvent ) : void
{
	var stockQuoteEvent : GetStockQuoteEvent = GetStockQuoteEvent( event );	     	
	var symbol : String = stockQuoteEvent.symbol;
	quoteId = stockQuoteEvent.quoteId;
	var delegate : StockMarketDelegate = new StockMarketDelegate( this );
	delegate.getQuoteForSymbol( symbol );
}
		
public function onResult( event : ResultEvent = null ) : void
{
	//simulate a result from service
	var lastStockQuote : Number = Math.random() * 50 + 5;
	var stockQuote : StockQuote = model.stockQuoteManager.getStockQuote( quoteId );
	stockQuote.lastStockQuote = lastStockQuote;
	stockQuote.stockQuoteError = "";
}
		
public function onFault( event : FaultEvent = null ) : void
{
	var stockQuote : StockQuote = model.stockQuoteManager.getStockQuote( quoteId );
	stockQuote.lastStockQuote = NaN;
	stockQuote.stockQuoteError = "An error occured.";
}
</pre>

<p>Also, notice that in the example above we make use of stateless commands. Since the introduction of stateless commands in Cairngorm, new command instances are being created each time a Cairngorm event is dispatched (<a href="http://weblogs.macromedia.com/amcleod/archives/2006/05/cairngorm_2_-_f.cfm">see Alistair McLeod’s blog entry</a>). You can now securely save instance properties in your commands without fearing that the instance property will be modified by another Cairngorm event. Would your command not be stateless, our quoteId could be overwritten by a quoteId from another stock pod. When the command's onResult is triggered by the incoming response from the first remote service request, the response would map to a wrong StockQuote object. But thankfully, we don't need to think about that anymore. ;)</p>

<p><strong>Spinning it a wee bit further.</strong></p>

<p>Notice, that your manager object could contain other functionality that applies to all pods. Think about a domain model that suits your use case best. </p>

<p>Furthermore, in a slightly more elaborate use case it might be significant that the onResult handler in GetStockQuoteCommand requests the currently up-to-date StockQuote object from the manager object as it does in the example shown. While the command is waiting for a response for a request to a remote service, the state of the RIA could change. When the response comes in, the manager object might want to return a different StockQuote object or not a StockQuote object at all. </p>

<p>For example, the end user might be able to close certain stock quote pods. In this case, its representing StockQuote model object may also have been deleted. On subsequent requests to the StockQuote object, the manager object might want to throw an exception. This exception might be handled differently by the command.</p>

<p>You might want to check out the <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration3/DashboardIteration3.html">complete source</a> (right click on the sample app and choose “View Source” or download it as a ZIP file).</p>]]>
</content>
</entry>
<entry>
<title>Cairngorm Sample – How Business Logic Can Manage Views</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/auhlmann/archives/2006/06/cairngorm_sampl.html" />
<modified>2006-06-01T13:26:22Z</modified>
<issued>2006-06-01T12:20:18Z</issued>
<id>tag:weblogs.macromedia.com,2006:/auhlmann//62.11093</id>
<created>2006-06-01T12:20:18Z</created>
<summary type="text/plain">There are many ways to update your views when your server- or client side business logic changes. The strategy you find me usually recommending is the ModelLocator strategy, which leverages the Flex binding feature. See Steven Webster&apos;s article for more...</summary>
<author>
<name>auhlmann</name>

<email>auhlmann@adobe.com</email>
</author>
<dc:subject>Cairngorm</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/auhlmann/">
<![CDATA[<p>There are many ways to update your views when your server- or client side business logic changes. The strategy you find me usually recommending is the ModelLocator strategy, which leverages the Flex binding feature. See <a href="http://www.adobe.com/devnet/flex/articles/cairngorm_pt3_03.html">Steven Webster's article</a> for more information.</p>

<p>Basically, your views bind to properties that are retrieved from your ModelLocator. These properties can be changed from your Commands, other business logic or other views and once changed; all listening views are updated seamlessly.</p>

<p>Since many of the Cairngorm examples out there are meant to be easy to understand, they often just show these properties exposed as single properties on the ModelLocator. Once your RIA grows in size, this indeed can be quite limiting. I’ll showcase another Cairngorm sample application that focuses on how you can improve your architecture with investing in slightly more advanced business logic. The sample application is a stock market dashboard that allows users to retrieve price quotes on a company stock. From time to time I’ll add features to this application, to showcase some possible ways to architect a Cairngorm application. This version of it will use <a href="http://weblogs.macromedia.com/swebster/archives/Cairngorm2b3.zip">Cairngorm for Flex 2 Beta 3</a>.</p>]]>
<![CDATA[<p><strong>Iteration 1 - The simplest thing that could possibly work</strong></p>

<p>But let’s first look at the very simplest possible solution with still leveraging MVC principles advocated by Cairngorm. The stock market dashboard in its first iteration just contains a single pod with minimal UI controls. <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration1/DashboardIteration1.html">See example</a>.</p>

<p>With pressing the “Get Quote” button the user dispatches a Cairngorm event that is handled by a Command instance to request a new quote. </p>

<p>StockMarketPod.mxml dispatches the Cairngorm event on behalf of a Button’s click event:</p>

<pre>&lt;mx:Button label="Get Quote" click="getQuoteForSymbol();"/&gt;</pre>

<p>And the corresponding mx:Script tag:</p>

<pre>
import org.nevis.cairngorm.samples.dashboard.events.GetStockQuoteEvent;									
private function getQuoteForSymbol() : void
{
	var event : GetStockQuoteEvent = new GetStockQuoteEvent( symbolTextInput.text );
	dispatchEvent( event );
}
</pre>

<p>GetStockQuoteCommand handles the Cairngorm event and asks a business delegate class (StockMarketDelegate) for a quote.</p>

<pre>
public function execute( event : CairngormEvent ) : void
{
	var symbol : String = GetStockQuoteEvent( event ).symbol;
	var delegate : StockMarketDelegate = new StockMarketDelegate( this );
	delegate.getQuoteForSymbol( symbol );
}
</pre>

<p>In a real world scenario this would be most likely a server side call, but for the sake of simplicity in this demo, I’ve commented the code that would be needed to call a remote service in the business delegate. </p>

<p>StockMarketDelegate.as just calls back to the Command immediately. Notice that if the user enters a symbol “fail”, the Command’s onFault handler will be invoked. </p>

<pre>
public function StockMarketDelegate( responder : Responder )
{
	//disabled for demo
	//this.service = ServiceLocator.getInstance().getService( "stockMarketDelegate" );
	this.responder = responder;
}
		
public function getQuoteForSymbol( symbol : String ) : void
{
	//disabled for demo
	//var call : AsyncToken = service.getQuoteForSymbol( symbol );
	//call.resultHandler = responder.onResult;
	//call.faultHandler = responder.onFault;
	if( symbol == "fail" )
	{
		responder.onFault();
	}
	else
	{
		responder.onResult();
	}
}
</pre>

<p>Our StockMarketPod view just needs two information from the application’s business logic. </p>

<ul>
<li>The answer to the quote (the stock price)</li>
<li>An error message, that communicates to the user if a request fails.</li>
</ul>

<p>Because this is so simple, I have just created two properties directly on the ModelLocator.</p>

<pre>
public var lastStockQuote : Number;
public var stockQuoteError : String;
</pre>

<p>GetStockQuoteCommand can then just change these values in the onResult or onFault handler. For this demo purpose, it performs some dummy calculations to simulate the remote service result.</p>

<pre>
public function onResult( event : ResultEvent = null ) : void
{
	//simulate a result from service
	var stockQuote : Number = Math.random() * 50 + 5;
	model.lastStockQuote = stockQuote;
	model.stockQuoteError = "";
 }
		
public function onFault( event : FaultEvent = null ) : void
{
	model.lastStockQuote = NaN;
	model.stockQuoteError = "An error occured.";
}
</pre>

<p>The StockMarketPod view can bind to those properties and further format the result based on its presentation needs:</p>

<pre>
&lt;mx:FormItem label="Symbol"&gt;
	&lt;mx:Label text="{ formatQuote( model.lastStockQuote ) }"/&gt;
&lt;/mx:FormItem&gt;
&lt;mx:FormItem&gt;
	&lt;mx:Label text="{ model.stockQuoteError }"/&gt;
&lt;/mx:FormItem&gt;
</pre>

<p>And the formatting logic of a mx:Script block.</p>

<pre>
private function formatQuote( quote : Number ) : String
{
	return ( isNaN( quote ) ) ? "" : String( quote );
}
</pre>

<p>Note that this type of code could be refactored and extracted out from the view into a unit-testable utility class.</p>

<p></p>

<p><strong>Iteration 2 - Creating business logic that fit your needs</strong></p>

<p>Now, the above example is the simplest thing that could possibly work. As your RIA grows in size this can be limiting. You may find that your ModelLocator instance is “overcrowded” with properties that you might even forget what they are needed for. You might also run into naming conflicts with other properties designed for different use cases.</p>

<p>A common refactoring is to create business objects that encapsulate the properties of your use case. These business objects can represent the information that your views need in a business context. You can design them at a granularity that fits your use case best. For example in a larger RIA you might want to think about a number of classes to represent your use case. Your views may then bind to these business objects or to properties of it. Your views might bind to other application objects that translate your business objects to a form that’s more useful to your views. </p>

<p>This way, your ModelLocator might better communicate its intent as it’s much easier for developers to grasp what business logic your application contains. </p>

<p>In our stock market dashboard, we could e.g. encapsulate the lastStockQuote and stockQuoteError properties in a simple business object:</p>

<pre>
package org.nevis.cairngorm.samples.dashboard.model
{
	public class StockQuote
	{
		[Bindable]
		public var lastStockQuote : Number;
		[Bindable]
		public var stockQuoteError : String;
	}
}
</pre>

<p>Note, that in a true business object you would probably not even have a property that directly holds a String with an error message. Instead, the business object would just hold an error type and other application objects would translate that error type to e.g. a String representation, which could then be used by views. </p>

<p>Our ModelLocator would just define a single property representing a stock market pod view in a business context. E.g. with </p>

<pre>
public var stockQuote : StockQuote = new StockQuote ();
</pre>

<p>And our view would change to this:</p>

<pre>
&lt;mx:FormItem label="Symbol"&gt;
	&lt;mx:Label text="{ formatQuote( model.stockQuote.lastStockQuote ) }"/&gt;
&lt;/mx:FormItem&gt;
&lt;mx:FormItem&gt;
	&lt;mx:Label text="{ model.stockQuote.stockQuoteError }"/&gt;
&lt;/mx:FormItem&gt;
</pre>

<p>You might want to check out the <a href="http://www.alex-uhlmann.de/flash/adobe/blog/dashboard/iteration2/DashboardIteration2.html">complete source</a> (right click on the sample app and choose “View Source” or download it as a ZIP file).</p>]]>
</content>
</entry>

</feed>