Wednesday, September 07, 2011
Adobe MAX 2010: Performance Tips and Tricks for Flex and Flash Development
Saturday, August 20, 2011
Intro to Spark Containers
- Types of Spark Containers
- Types of IVisualElements
- Group Basics
- The multi-faces of DOM
- Lesser known container features
- Internals of Group and SkinnableContainer
- Performance considerations
I'm moving
Saturday, June 18, 2011
Binding Dependencies
spark.components.VideoPlayer
, volume
is dependent on the videoDisplay.volume
property. Usually to make such a property bindable, you add an event listener to know when your dependent property changes. In this case, if you check out VideoPlayer.partAdded()
, you can see code like that. However, when I started using the presentation model pattern, this issue seemed to keep coming up quite frequently.
public class Order
{
[Bindable]
public var billingState:String;
[Bindable]
public var shippingState:String;
}
<s:Form>
<s:FormItem label="Billing State">
<s:DropDownList selectedItem="@{ presentationModel.order.billingState }">
<s:ArrayList>
<fx:String>AL</fx:String>
<fx:String>AS</fx:String>
<fx:String>AZ</fx:String>
<fx:String>AR</fx:String>
<fx:String>CA</fx:String>
<fx:String>CO</fx:String>
<fx:String>CT</fx:String>
<fx:String>DE</fx:String>
</s:ArrayList>
</s:DropDownList>
</s:FormItem>
<s:FormItem label="Shipping State">
<s:DropDownList selectedItem="@{ presentationModel.order.shippingState }">
<s:ArrayList>
<fx:String>AL</fx:String>
<fx:String>AS</fx:String>
<fx:String>AZ</fx:String>
<fx:String>AR</fx:String>
<fx:String>CA</fx:String>
<fx:String>CO</fx:String>
<fx:String>CT</fx:String>
<fx:String>DE</fx:String>
</s:ArrayList>
</s:DropDownList>
</s:FormItem>
<s:FormItem label="California Question1"
includeInLayout="{ presentationModel.order.shippingState == 'CA' && presentationModel.order.billingState == 'CA' }"
visible="{ presentationModel.order.shippingState == 'CA' && presentationModel.order.billingState == 'CA' }">
<s:TextInput />
</s:FormItem>
<s:FormItem label="California Question2"
includeInLayout="{ presentationModel.order.shippingState == 'CA' && presentationModel.order.billingState == 'CA' }"
visible="{ presentationModel.order.shippingState == 'CA' && presentationModel.order.billingState == 'CA' }">
<s:TextInput />
</s:FormItem>
</s:Form>
presentationModel.order.shippingState == 'CA' && presentationModel.order.billingState == 'CA'
is repeated 4 times, the ampersands have to be escaped, and overall it's just quite ugly. Now, one of the neat tricks I've learned is that you can spruce it up by doing something like:
<fx:Declarations>
<fx:Boolean id="showCaliforniaQuestions">
{presentationModel.order.shippingState == "CA" &&
presentationModel.order.billingState == "CA"}
</fx:Boolean>
</fx:Declarations>
...
<s:FormItem label="California Question1"
includeInLayout="{ showCaliforniaQuestions }"
visible="{ showCaliforniaQuestions }">
<s:TextInput />
</s:FormItem>
<s:FormItem label="California Question2"
includeInLayout="{ showCaliforniaQuestions }"
visible="{ showCaliforniaQuestions }">
<s:TextInput />
</s:FormItem>
<s:FormItem label="California Question1"
includeInLayout="{ presentationModel.showCaliforniaQuestions }"
visible="{ presentationModel.showCaliforniaQuestions }">
<s:TextInput />
</s:FormItem>
<s:FormItem label="California Question2"
includeInLayout="{ presentationModel.showCaliforniaQuestions }"
visible="{ presentationModel.showCaliforniaQuestions }">
<s:TextInput />
</s:FormItem>
public class MyPM
{
public function MyPM()
{
super();
}
[Bindable]
public var order:Order = new Order();
public function get showCaliforniaQuestions():Boolean
{
return order.shippingState == "CA" && order.billingState == "CA";
}
}
showCaliforniaQuestions
isn't Bindable. Now, to make it Bindable, we need to add Bindable metadata on top, add event listeners (or use a BindingWatcher) to let us know when the shipping state or the billing state changes, and dispatch a new binding event when we get notified that the shipping or billing state changes. This turns out to be quite a lot of extra, ugly code, which means most people just end up keeping this logic in the View because practically it's just too much work and too ugly to move it to the Presentation Model. This is all fine, but this kept issue kept cropping up in practice, so I finally sat down to come up with a more palatable option.
[Bindable(event="showCaliforniaQuestionsChanged",dependentProperty="order.shippingState")]
[Bindable(event="showCaliforniaQuestionsChanged",dependentProperty="order.billingState")]
public function get showCaliforniaQuestions():Boolean
{
return order.shippingState == "CA" && order.billingState == "CA";
}
showCaliforniaQuestions
as Bindable, where that binding is dependent on the order.shippingState
and order.billingState
properties. The Parsley metadata processor will step in and handle everything else. I personally like this solution a lot as it piggy-backs off of the Flex SDK framework's Bindable metadata and just extends it for our purpose. It's easy to use and pushes our logic into Presentation Model, which makes our code cleaner and more importantly, testable.Thursday, June 09, 2011
Why Presentation Models can be confusing
- Separate out the state and behavior of the view from the presentation of the View itself
- Provide a GUI agnostic, testable interface
- Provide a consisten, performant pattern that developers can easily follow
- The View should contain very little logic--only GUI specific, layout implementation should be contained in the View
- The View should use databinding to grab information from the Presentatio Model
- The View should call methods directly into the PM (see FAQ for description of right level of abstraction)
- The View should attach Flash event listeners on the PM to receive any event information (if using Parsley, the View should not communicate to anyone using Parsley messaging as configuring a display object in Parsley is a huge performance hit)
- The PM should hold the logic, state, and data of the user interface. It is essentially an abstract, non-GUI dependent abstraction of a View
- The PM controls what the View displays (how to display it is up to the View)
- The View calls into the PM via public methods. The PM then takes those actions and talks to the Domain Layer.
- For the PM to talk to the View, it should use properties with data-binding or Flash events.
- <s:Button id="submitButton" click="{ myPM.submitButton_clickHandler }" />
- <s:Button id="submitButton" click="myPM.onSubmitButton(busIdTI.text)" />
- <s:Button id="submitButton" click="myPM.setBusId(parseInt(busIdTI.text))" />
- <s:Button id="submitButton" click="myPM.unsubscribe(); myPM.setCurrentBus(new Bus(parseInt(busIdTI.text))); myPM.subscribe();" />
- http://martinfowler.com/eaaDev/PresentationModel.html
- http://blogs.adobe.com/paulw/archives/2007/10/presentation_pa_3.html
- http://blogs.msdn.com/b/erwinvandervalk/archive/2009/08/14/the-difference-between-model-view-viewmodel-and-other-separated-presentation-patterns.aspx
- http://artinflex.blogspot.com/2010/11/presentation-model-implemented-in.html
- http://www.spicefactory.org/parsley/docs/2.2/manual/mvc.php
- http://blogs.adobe.com/tomsugden/2009/08/applying_the_presentation_mode.html
Monday, February 22, 2010
When to use what Spark Container
As always, I'm disappointed with the amount I blog. One strategy I'm going to take is to take questions asked on forums that I think are interesting and provide an answer. So, for this first question comes from a forum post.
This gets me really confused on which container i should use with my project.
For example, what's the difference between:
<s:Group>
<s:layout>
<s:HorizontalLayout />
</s:layout>
</s:Group>
...and...
<s:HGroup>
</s:HGroup>
...or even...
<mx:HBox>
</mx:HBox>
I'm sorry if i'm saying something wrong but it makes me waste so much time thinking on which one i should use cause, for me, all of them do exactly the same.
One other thing is if i need to do a container with a background color. What should i use?
<mx:Canvas backgroundcolor="{color}">
<MyComponents />
</mx:Canvas>
...or...
<s:Group>
<s:Rect>
<s:fill>
<s:SolidColor color="{color}" />
</s:fill>
</s:Rect>
<MyComponents />
</s:Group>
Can anyone tell me which one is the best pratice now for Flex 4?
Answer:
We hope you can use the new Spark components whenever possible. Group is the basic, chromeless container. SkinnableContainer is our basic container with chrome (for instance Panel extends SkinnableContainer). One of the cool new things you can do in spark is swap layouts. For instance, you can use a HorizontalLayout with a Group, or you can even create a custom layout and use it with your List. This is really powerful, and this separation between a container and the layout make a lot of things easier, That said, for really common use-cases, we found some people were annoyed with having to type:
<s:Group>
<s:layout>
<s:VerticalLayout horizontAlign=".." />
</s:layout>
...
</s:Group>
And people were used to having HBox and VBox. Because of this, we created helper classes, HGroup and VGroup, which extend Group and have the layout object baked in. They don't really add any functionality...they are just there as a shortcut. To make it easier we also proxy up some layout-dependent properties on to the container, like horizontalAlign and verticalAlign.
In summary:
HBox, VBox, and Canvas are replaced by one component, Group. However their functionality is really replaced by HorizontalLayout, VerticalLayout, and BasicLayout, respectively. We have helper objects HGroup and VGroup to make common tasks easier. If you want a skinnable form of those components (something with chrome), use SkinnableContainer and change the layout (we did not provide helper classes HSkinnableContainer and VSkinnableContainer because we don't think it's as common of a use-case).
As a side note, I think you should always switch to using these new Spark container classes whenever possible. We think they are more flexible because of swappable layouts, and they also support GraphicElements directly, while MX containers do not. In addition, the Spark classes are made to be lighter-weight and more performant. For instance, they don't have scrollbars built in, and they are chromeless. An exception is if you used Canvas and advanced constraints before. We haven't created an AdvancedConstraint layout yet.
As per the backgroundColor part of your question, you could composite it together like you did in the Group:
<s:Group>
<s:Rect>
<s:fill>
<s:SolidColor color="{color}" />
</s:fill>
</s:Rect>
<MyComponents />
</s:Group>
However, ideally, I'd tell you to use SkinnableContainer and place the Rectangle in the SkinnableContainer's skin. This way you're segregating the content of the component from the look of the component. This is part of the "container with chrome (SkinnableContainer) vs. container with no chrome (Group)". As we started out down the Spark architecture path, we really pushed hard for people to use this new skinning model, and in this case, we would push people to put the <s:Rect> in to the skin, but in balancing our "theoretical ideal of the skin vs. the component" and the usability of the framework, we received feedback that for common situations we need to provide styles. Because of this, our default SkinnableContainer skin already has a background rectangle in it, and you can control its color with the backgroundColor style, like:
<s:SkinnableContainer backgroundcolor="red">
...
</s:SkinnableContainer>
We baked this background and backgroundColor style in to the SkinnableContainer component for ease-of-use, so you don't have to create a skin just for simple changes. However, if you want something really complex (like a rounded rectangle as the background, then you should re-skin the SkinnableContainer).
Hope this helps answer a lot of questions.
-Ryan