Home >
Note: This is excerpted from Chapter 3 of the Rough Cuts version of Enterprise Development with Flex. This book is still in progress, and you can get access to it now.
Rough Cuts is a service from Safari Books Online that gives you early access to content on cutting-edge technologies -- before it's published. It lets you literally read the book as it is being written.
Chapter 3. Building an Enterprise Framework
Table of Contents, Part 1
Upgrading Existing Flex Components
Introducing Component Library clear.swc
Creating a Value-Aware CheckBox
Resources as Properties of UI Controls
Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.
There is no such thing as perfect design. Flex framework is evolving, and we are grateful that software engineers from Flex team made this framework extendable. Because this book covers the use of Flex framework in enterprise software development, we will identify and enhance those components that are widely used in business RIA.
For the majority of the enterprise applications, development comes down to a few major activities:
-
Creating data grids
-
Working with forms
-
Validating data
-
Printing
If you, the architect, can achieve improvements in each of these areas by automating common tasks, application developers will spend less time writing the same mundane code over and over again. The key is to encapsulate such code inside reusable Flex components, to create smarter components that can be collected into libraries.
Chapter 1, Comparing Selected Flex Frameworks reviewed such architectural frameworks as Cairngorm, PureMVC and Mate, which mainly helped with separating the code into tiers, but now you'll learn how to build another type of a framework by enhancing existing Flex components. Specifically, this chapter demonstrates how to build a framework that radically simplifies creation of data entry applications by:
-
Identifying common reusable components, which in turn reduces the number of errors inevitably introduced during manual coding
-
Encapsulating implementation of architectural patterns inside selected components
-
Defining best practices and implement them in concrete components rather than just describing them on paper
You'll learn how to inherit your components from the existing
ones, starting with the basic techniques while extending a simple
CheckBox, then approaching more
complex ComboBox component. The
remainder of the chapter is devoted to extending components that
every enterprise application relies on, namely DataGrid, Form and
Validator.
By providing a framework that integrates the work of programmers, business analysts, designers, and advanced users, you can drastically simplify the development of enterprise applications.
Every Web developer is familiar with Cascading Style Sheets
(CSS) that allow designers define and change the look and feel of
the applications without the need to learn programming. As you'll
learn in this chapter, Business Style Sheets (BSS) serve a similar
role for enterprise application developers, enabling software
developers to attach a remote data set to a component with minimum
coding. For example, you'll see how a simple resource file can
instruct a ComboBox (or any other
component) where to get and how to display the data. Think of it as
a data skinning. With BSS you can develop artifacts that are highly
reusable across enterprise applications.
Along the way, you'll learn more about BSS and other techniques for enhancing and automating Flex components. Although you won't be able to build an entire framework here (the challenges of printing and reporting are covered in the last chapter), you'll get a good start in mastering valuable skills that any Flex architect and component developer must have.
Flex evolved as Flash framework from HTML object model, and the
base set of Flex controls capitalized on simplicity of HTML. The
price that Flex developers have to pay for this is that each
control has its own (different) set of properties and behaviors.
This can make building an enterprise framework a challenge.
Consider a CheckBox control as an
example.
To quickly and easily integrate CheckBox into a variety of frameworks, developers
would prefer the component to have a unified property value (on or off ) that's easily bindable to
application data. Currently, Flex's CheckBox has a property called selected and developers need to write code
converting Yes/No the data
into the true or false that the selected property expects. If you later use
another control, you must then convert these Yes/No values into the form that the new
control requires. Clearly some common ground would reduce the
amount of redundant coding.
The sections that follow will take a closer look at the
CheckBox as well as other major Flex
components that every application needs, identify what are they
missing, and how to enhance them.
As you may remember from Chapter 1, Comparing Selected Flex Frameworks, Clear Toolkit's component library, clear.swc, contains a number of enhanced Flex components (Figure 3.1, “The com.farata.components package from clear.swc”). Specifically, this component library consists of three packages
-
com.farata.components
-
com.farata.grid
-
com.farata.printing
To demonstrate how you can extend components, in the following sections we'll explain how we built some of the components from the package com.farata.component. Later you can use these discussions for reference, if you decide to built a similar (or better) library of components. (Some of the classes from the other two packages will be discussed in Chapter 11 of this book.)
Note
You can find the source code of all components described in this chapter in the clear.swc component library. The code of some of the components explained here was simplified to make explanations of the process of extending Flex components easier. Neither this chapter nor the book as a whole is meant to be a manual for the open source clear.swc library. If you just want to use clear.swc components, refer to https://sourceforge.net/projects/cleartoolkit/ where the asdoc-style API and the source code of each component from clear.swc is available.
You can use clear.swc independently by linking it to your Flex project. To help you understand how its components can help you, the following sections examine simplified versions of some of the library's controls.
The CheckBox in Example 3.1,
“CheckBox with value and text properties” has been
enhanced with additional value and
text properties. You can specify which
value should trigger turning this control into the on/off
position.
Example 3.1. CheckBox with value and text properties
package com.farata.controls {
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import mx.controls.CheckBox;
import mx.events.FlexEvent;
public class CheckBox extends mx.controls.CheckBox {
public var onValue:Object=true;
public var offValue:Object=false;
private var _value:*;
public function set text(o:Object):void {
value = o;
}
public function get text():Object {
return value;
}
[Bindable("valueCommit")]
public function set value(val:*) :void {
_value = val;
invalidateProperties();
dispatchEvent(new FlexEvent (FlexEvent.VALUE_COMMIT));
}
public function get value():Object {
return selected?onValue:offValue;
}
override protected function commitProperties():void {
if (_value!==undefined)
selected = (_value == onValue);
super.commitProperties();
}
}
}
This CheckBox will automatically
switch itself into a selected or unselected state: Just add it to
your view, set the on and off values, and either assign the
String or an Object value to it. Please note that the
value setter calls the function
invalidateProperties(), which
internally schedules the invocation of the function commitProperties() on the next UI refresh
cycle.
The commitProperties() function
enables you to make changes to all the properties of a component in
one shot. That's why we set the value of the selected property
based on the result of comparison of _value and onValue in
this function.
Example 3.2, “Test application for the value-aware
CheckBox” is a test application illustrating how to use
this CheckBox with the resulting
interface shown in Figure 3.2,
“Testing the value-aware CheckBox”. To run a test,
click the first Set OnValue= button to teach the CheckBox to turn itself on when the value Male is assigned, and off when its property text has the value
of Female. Then, click the
first or second cbx_test.text button to assign a value to the newly
introduced property text of this CheckBox, and watch how its state changes.
Example 3.2. Test application for the value-aware CheckBox
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:clear="com.farata.controls.*" layout="vertical">
<clear:CheckBox id="cbx_test" label="Assign me a value" />
<mx:Button label="Set OnValue='Male' and offValue='Female'"
click="cbx_test.onValue='Male';cbx_test.offValue='Female';"/>
<mx:Button label="cbx_test.text='Male'" click="cbx_test.text='Male'" />
<mx:Button label="cbx_test.text='Female'" click="cbx_test.text='Female'" />
<mx:Button label="Set OnValue=Number('1') and offValue=Number('0')"
click="cbx_test.onValue=Number('1');cbx_test.offValue=Number('0');"/>
<mx:Button label="cbx_test.value='Number('1')'"
click="cbx_test.value =new Number('1')" />
<mx:Button label="cbx_test. value='Number('0')"
click="cbx_test.value =new Number('0')" />
</mx:Application>
This example demonstrates how to create a CheckBox that can center itself horizontally in
any container, including a data grid cell.
Although you could introduce an item renderer that uses a
CheckBox inside an HBox with the style horizontalAlign set to center, using a container inside the item rendered
negatively affect the data grid control's performance.
The better approach is to extend the styling of the CheckBox itself. Here is a code extension that
"teaches" a standard Flex CheckBox to
respond to the textAlign style if the
label property of the CheckBox is not defined:
Example 3.3. Self-centering solution for CheckBox
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void {
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (currentIcon) {
var style:String = getStyle("textAlign");
if ((!label) && (style=="center") ) {
currentIcon.x = (unscaledWidth - currentIcon.measuredWidth)/2;
}
}
}
In the code above, the x coordinate
of the CheckBox icon will be always
located in the center of the enclosing container. Because no
additional container is introduced, you can use this approach in
the DataGridColumn item renderer,
which is a style selector. When you use this enhanced CheckBox as a column item renderer, textAlign automatically becomes a style of this
style selector, and you can simply set textAlign=true on DataGridColumn.
Note
While developing enhanced components for the enterprise business framework, concentrate on identifying reusable functionality that application developers often need, program it once and incorporate it in the component itself.
The standard Flex CheckBox has a
Boolean property called enabled that
is handy when you want to disable the control. Unfortunately,
disabled a CheckBox is rendered as
grayed out. What if you want to use a CheckBox in some non-editable container, say in a
DataGridColumn and you want it to be
non-updatable but look normal.
The answer is to use a new class called CheckBoxProtected, which includes an additional
property updatable. Its trick is to
suppress standard keyboard and mouse click processing. Overriding
event handlers by adding
if (!updateable) return;
works like charm! Example 3.4, “Class CheckBoxProtected” lists the complete code.
Example 3.4. Class CheckBoxProtected
package com.farata.controls
{
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import mx.controls.CheckBox;
public class CheckBoxProtected extends mx.controls.CheckBox {
public var updateable:Boolean = true;
public function CheckBoxProtected() {
super();
addEventListener(MouseEvent.CLICK, onClick);
}
private function onClick (event:MouseEvent):void {
dispatchEvent(new Event(Event.CHANGE));
}
override protected function keyDownHandler(event:KeyboardEvent):void {
if (!updateable) return;
super.keyDownHandler(event);
}
override protected function keyUpHandler(event:KeyboardEvent):void {
if (!updateable) return;
super.keyUpHandler(event);
}
override protected function mouseDownHandler(event:MouseEvent):void {
if (!updateable)return;
super.mouseDownHandler(event);
}
override protected function mouseUpHandler(event:MouseEvent):void {
if (!updateable)return;
super.mouseUpHandler(event);
}
override protected function clickHandler(event:MouseEvent):void {
if (!updateable)return;
super.clickHandler(event);
}
}
}
To test the protected CheckBox use
Example 3.5,
“Test application for CheckBoxProtected”.
Example 3.5. Test application for CheckBoxProtected
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:clear="com.farata.controls.*" layout="vertical">
<clear:CheckBoxProtected updateable="false"
label="I am protected" fontSize="18"/>
<mx:CheckBox enabled="false"
label="I am disabled" fontSize="18"/>
</mx:Application>
Running this application produces the results in Figure 3.3, “Running CheckBoxProtectedApp”, which shows the difference between the protected and disabled checkboxes.
Why not use extensibility of Flex framework to its fullest? This chapter is about what you can do with Flex components. Armed with this knowledge you'll make your own decisions about what do you want to do with them.
For example, think of a CheckBox
with a third state. The underlying data can be Yes, No and null. If the value is null (the third state), the CheckBox needs to display a different image, say a
little question mark inside. In addition to supporting three states
(selected, unselected and null) this
control should allow an easy switch from one state to another. Such
an enhancement includes a skinning task – create a new skin
(with a question mark) in Photoshop and ensure that the control
switches to this state based on the underlying data. For a working
example, see CheckBox3Stated in the
clear.swc component
library.
The CheckBox is easiest to enhance
because it's one of the simplest controls, having only two states
(on or off). You can apply the same principles
to a more advanced ComboBox, however.
Identify reusable functionality, program it once, and incorporate
it into the component.
What if, for example, you need to programmatically request a
specific value to be selected in a ComboBox? The traditional approach is to write
code that loops through the list of items in the ComboBox data provider and manually work with the
selectedIndex property. To set
Texas as a selected value of
a ComboBox that renders states, you
could use:
var val:String; val= 'Texas' ;
for (var i: int = 0; i < cbx.dataProdider.length; i++) {
if ( val == cbx_states.dataProvider[i].label) {
cbx_states.selectedIndex = i;
break;
}
}
The downside of this approach is that if your application has
fifty ComboBox controls, several
developers will be writing similar loops instead of a single line,
such as cbx_states.value="Texas".
Unfortunately, ComboBox does not
provide a specific property that contains the selected value. It
has such properties as labelField,
selectedIndex, and selectedItem. Which one of them is actually a data
field? How to search by value? Do you really care what's the number
of the selected row in the ComboBox?
Not at all you need to know the selected value.
Let's revisit the code snippet above. The labelField of a ComboBox knows the name of the property from the
objects stored in backing collection. But what about the data field
that corresponds to this label (say, in case of Texas, a good candidate to be considered as the
ComboBox data could be TX)? Currently, finding such data is a
responsibility of the application programmer.
Even if you are OK with writing these loops, considering an
asynchronous nature of populating data providers, this code may
need to wait until the data will arrive from the server. It would
be nice though if you could simply assign the value to a
ComboBox without the need to worry
about asynchronous flows of events.
Consider a List control, the
brother of the ComboBox. Say, the user
selected five items, and then decided to filter the backing data
collection. The user's selections will be lost. The List is also crying for another property that
remembers selected values and can be used without worrying about
the time of data arrival.
Example 3.6,
“Class com.farata.control.ComboBoxBase” offers a
solution: The class ComboBoxBase,
which extends ComboBox by adding the
value property (don't confuse it with
). After
introducing the value property, it
uses the dataField property to tells
the ComboBox the name of the data
field in the object of its underlying data collection that
corresponds to this value. The new
dataField property enables you to use
any arbitrary object property as ComboBox data.
You'll also notice one more public property: keyField, which is technically a synonym of
dataField. You can use keyField to avoid naming conflicts in situations
where the ComboBoxBase or its
subclasses are used inside other objects (say DataGridColumn) that also have a property called
dataField.
Example 3.6. Class com.farata.control.ComboBoxBase
package com.farata.controls {
import flash.events.Event;
import mx.collections.CursorBookmark;
import mx.collections.ICollectionView;
import mx.collections.IViewCursor;
import mx.controls.ComboBox;
import mx.controls.dataGridClasses.DataGridListData;
import mx.controls.listClasses.ListData;
import mx.core.mx_internal;
use namespace mx_internal;
public class ComboBoxBase extends ComboBox {
public function ComboBoxBase() {
super();
addEventListener("change", onChange);
}
// Allow control to change dataProvider data on change
private function onChange(event:Event):void {
if (listData is DataGridListData) {
data[DataGridListData(listData).dataField] = value;
}else if (listData is ListData && ListData(listData).labelField
in data) {
data[ListData(listData).labelField] = value;
}
}
protected function applyValue(value:Object):void {
if ((value != null) && (dataProvider != null)) {
var cursor:IViewCursor = (dataProvider as
ICollectionView).createCursor( );
var i:uint = 0;
for (cursor.seek( CursorBookmark.FIRST ); !cursor.afterLast;
cursor.moveNext(), i++) {
var entry:Object = cursor.current;
if ( !entry ) continue;
if ( (dataField in entry && value == entry[dataField])) {
selectedIndex = i;
return;
}
}
}
selectedIndex = -1;
}
private var _dataField:String = "data";
private var _dataFieldChanged:Boolean = false;
[Bindable("dataFieldChanged")]
[Inspectable(category="Data", defaultValue="data")]
public function get dataField():String { return _dataField; }
public function set dataField(value:String):void {
if ( _dataField == value)
return;
_dataField = value;
_dataFieldChanged = true;
dispatchEvent(new Event("dataFieldChanged"));
invalidateProperties();
}
public function get keyField():String { return _dataField; }
public function set keyField(value:String):void {
if ( _dataField == value)
return;
dataField = value;
}
private var _candidateValue:Object = null;
private var _valueChanged:Boolean = false;
[Bindable("change")]
[Bindable("valueCommit")]
[Inspectable(defaultValue="0", category="General", verbose="1")]
public function set value(value:Object) : void {
if (value == this.value)
return;
_candidateValue = value;
_valueChanged = true;
invalidateProperties();
}
override public function get value():Object {
if (editable)
return text;
var item:Object = selectedItem;
if (item == null )
return null;
return dataField in item ? item[dataField] : null/*item[labelField]*/;
}
override public function set dataProvider(value:Object):void {
if ( !_valueChanged ) {
_candidateValue = this.value;
_valueChanged = true;
}
super.dataProvider = value;
}
override public function set data(data:Object):void {
super.data = data;
if (listData is DataGridListData) {
_candidateValue = data[DataGridListData(listData).dataField];
_valueChanged = true;
invalidateProperties();
}else if (listData is ListData && ListData(listData).labelField
in data) {
_candidateValue = data[ListData(listData).labelField];
_valueChanged = true;
invalidateProperties();
}
}
override protected function commitProperties():void {
super.commitProperties();
if (_dataFieldChanged) {
if (!_valueChanged && !editable)
dispatchEvent( new Event(Event.CHANGE) );
_dataFieldChanged = false;
}
if (_valueChanged) {
applyValue(_candidateValue);
_candidateValue = null;
_valueChanged = false;
}
}
public function lookupValue(value:Object, lookupField:String = null):Object {
var result:Object = null;
var cursor:IViewCursor = collectionIterator;
for (cursor.seek(CursorBookmark.FIRST);!cursor.afterLast;cursor.moveNext()) {
var entry:Object = cursor.current;
if ( value == entry[dataField] ) {
result = !lookupField ? entry[labelField] : entry[lookupField];
return result;
}
}
return result;
}
}
}
The new property value is assigned
in the following setter function:
[Bindable("change")]
[Bindable("valueCommit")]
[Inspectable(defaultValue="0", category="General", verbose="1")]
public function set value(value:Object) : void {
if (value == this.value)
return;
_candidateValue = value;
_valueChanged = true;
invalidateProperties();
}
Notice when the function turns on the flag _valueChanged, invalidateProperties()internally schedules a call
to the method commitProperties() to
ensure that all changes will be applied in the required sequence.
In the example's case, the code in the commitProperties() function ensures that the value
of the dataField is processed before
explicit changes to the value
property, if any.
ComboBox is an asynchronous control
that can be populated by making server-side call. There is no
guarantee that the remote data has arrived by the time when and
when you assign some data to the value
property. The _candidateValue in the
value setter is a temporary variable
supporting deferred assignment in the method commitProperties().
The function commitProperties()
broadcasts the notification that the value has been changed (in case if some other
application object is bound to this value) and passes the
_candidateValue to the method
applyValue().
override protected function commitProperties():void {
super.commitProperties();
if (_dataFieldChanged) {
if (!_valueChanged && !editable)
dispatchEvent( new Event(Event.CHANGE) );
_dataFieldChanged = false;
}
if (_valueChanged) {
applyValue(_candidateValue);
_candidateValue = null;
_valueChanged = false;
}
}
The method applyValue() loops
through the collection in the dataProvider using the IViewCursor iterator. When this code finds the
object in the data collection that has a property specified in the
dataField with the same value as the
argument of this function, it marks this row as selected.
protected function applyValue(value:Object):void {
if ((value != null) && (dataProvider != null)) {
var cursor:IViewCursor = (dataProvider as
ICollectionView).createCursor( );
var i:uint = 0;
for (cursor.seek( CursorBookmark.FIRST ); !cursor.afterLast;
cursor.moveNext(), i++) {
var entry:Object = cursor.current;
if ( !entry ) continue;
if ( (dataField in entry && value == entry[dataField])) {
selectedIndex = i;
return;
}
}
}
selectedIndex = -1;
}
Tags such as
[Inspectable(defaultValue="0",category="General",
verbose="1")]
ensure that corresponding properties will appear in property
sheets of ComboBoxBase in Flex
Builder's design mode (in this case under the category General with specified initial values in
defaultValue and verbose).
Metatags such as [Bindable("dataFieldChanged")] ensure that the
dataFieldChange event will be
dispatched (to those who care) whenever the value of the
dataField changes.
This small application TestComboBoxApp.mxml demonstrates the
use of the ComboBoxBase component.
Example 3.7. Using the ComboBoxBase component
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:clear="com.farata.controls.*" layout="vertical">
<mx:ArrayCollection id="cbData">
<mx:Array>
<mx:Object label="Adobe" data="ADBE" taxID="1111"/>
<mx:Object label="Microsoft" data="MSFT" taxID="2222"/>
<mx:Object label="Farata Systems" data="FS" taxID="3333"/>
</mx:Array>
</mx:ArrayCollection>
<clear:ComboBoxBase dataProvider="{cbData}" value="FS"/>
<clear:ComboBoxBase dataProvider="{cbData}" dataField="taxID" value="3333"/>
</mx:Application>
Both dropdowns use the same dataProvider. When you run Example 3.7,
“Using the ComboBoxBase component”'s application,
you'll see a window similar to
Figure 3.4, “Running an application with two
ComboBoxBase components”. window:
The first ComboBoxBase shows Farata
System because of the assignment value="FS" that compares it with values in the
data field of the objects from
cbData collection.
The second dropdown sets dataField="taxID" that instructs the ComboBox to use the value of taxID property in the underlying data collection.
If the code will assign a new value to taxID, i.e. an external data feed, the selection
in the ComboBox will change
accordingly. This behavior better relates to the real-world
situations where a collection of DTO with multiple properties
arrives from the server and has to be used with one or more
ComboBox controls that may consider
different DTO properties as their data.
Even more flexible solution for enhancing components to better
support your enterprise framework is through the use of a
programming technique that we call data
styling or Business Style Sheets (BSS). The basic
process is to create small files, called resources, and attach them as a property
to a regular UI component as well as a DataGrid column.
Example 3.8, “A CheckBox resource” illustrates this BSS technique and contains a small MXML file called YesNoCheckBoxResource.mxml:
Example 3.8. A CheckBox resource
<?xml version="1.0" encoding="utf-8"?>
<fx:CheckBoxResource
xmlns="com.farata.resources" xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:resources="com.theriabook.resources.*"
offValue = "N"
onValue = "Y"
textAlign="center"
>
</fx:CheckBoxResource>
Doesn't it look like a style to you? You can easily make it specific to a locale too by, for example changing the on/off values of Y/N to Д./Н, which mean Да/Нет in Russian, or Si/No for Spanish. When you think of such resources as of entities that are separate from the application components, you begin to see the flexibility of the technique. Isn't such functionality similar to what CSS is about?
As a matter of fact, it's more sophisticated than CSS because
this resource is a mix of styles and properties, as shown in
Example 3.9, “StateComboBoxResource with hard-coded
states”. Called StateComboBoxResource.mxml, this
resource demonstrates using properties (i.e. dataProvider) in a BSS. Such a resource can
contain a list of values such as names and abbreviations of
states:
Example 3.9. StateComboBoxResource with hard-coded states
<?xml version="1.0" encoding="utf-8"?>
<fx:ComboBoxResource
xmlns="com.farata.resources" xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:resources="com.theriabook.resources.*"
dropdownWidth="160"
width="160"
>
<fx:dataProvider>
<mx:Array>
<mx:Object data="AL" label="Alabama" />
<mx:Object data="AZ" label="Arizona" />
<mx:Object data="CA" label="California" />
<mx:Object data="CO" label="Colorado" />
<mx:Object data="CT" label="Connecticut" />
<mx:Object data="DE" label="Delaware" />
<mx:Object data="FL" label="Florida" />
<mx:Object data="GA" label="Georgia" />
<mx:Object data="WY" label="Wyoming" />
</mx:Array>
</fx:dataProvider>
</fx:ComboBoxResource>
Yet another example of a resource, Example 3.10, “Sample DepartmentComboResource configured for a remote destination” contains a reference to remote destination for automatic retrieval of dynamic data coming from a DBMS:
Example 3.10. Sample DepartmentComboResource configured for a remote destination
<?xml version="1.0" encoding="utf-8"?>
<fx:ComboBoxResource
xmlns="com.farata.resources" xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:resources="com.theriabook.resources.*"
width="160"
dropdownWidth="160"
destination="Employee"
keyField="DEPT_ID"
labelField="DEPT_NAME"
autoFill="true"
method="getDepartments"
>
</fx:ComboBoxResource>
As a matter of fact, you can't say from this code if the data is
coming from a DBMS or from somewhere else. That data is cleanly
separated from the instances of the ComboBox objects associated with this particular
resource and can be cached either globally (if the data needs to be
retrieved once) or according to the framework caching
specifications. When developing a business framework you may allow,
for example, lookup objects to be loaded once per application or
once per view. This flexibility doesn't exist in singleton-based
architectural frameworks. Frameworks built using the resource
technique/BSS, however, do allow the flexibility to lookup
objects.
Based on this resource file you can only say that the data comes
back from a remote destination called Employee, which is either a name of a class or a
class factory. You can also see that the method getDepartments() will return the data containing
DEPT_ID and DEPT_NAME that will be used with the enhanced
ComboBox described earlier in this
chapter (Example 3.6,
“Class com.farata.control.ComboBoxBase”).
In addition to such resources, however, you need a mechanism of
attaching them to Flex UI components. To teach a ComboBox to work with resources, add a
resource property to it:
private var _resource:Object;
public function get resource():Object
{
return _resource;
}
public function set resource(value:Object):void {
_resource = value;
var objInst:* = ResourceBase.getResourceInstance(value);
if(objInst)
objInst.apply(this);
}
The section "the section called “The
Base Class for Resources”" will detail the ResourceBase class. For now, concentrate on the
fact that the resource property
enables you to write something like this:
<fx:ComboBox resource="{DepartmentComboResource}"
Each of the enhanced UI components in your framework should
include such property. Because interfaces don't allow default
implementation of such setter and getter and because ActionScript
does not support multiple inheritance, the easiest way to include
this implementation of the resource
property to each control is by using the language compile-time
directive #include, which includes the
contents of the external file, say resource.as, into the code of your
components:
#include "resource.as"
Before going too deep into the BSS and resources approach, you
need to understand some key differences between styles and
properties. For instance, although simple dot notation
(myObject.resource=value) is valid
Flex syntax for properties, it is not allowed for styles. Instead,
application programmers have to use the function setStyle(). Suffice to say the StyleManager handles styles that can be cascading,
while properties can't cascade. From the framework developer's
point of view, properties allow defining classes with getters and
setters and take advantage of inheritance. With styles, you can't
do this. On the other hand, you can't add properties (i.e. value
and destination) to styles.
Designers of Flex framework separated styles from properties for
easier separation of internal processes – if an application
code changes the style, Flex frameworks performs some underground
work to ensure that cascading style conventions are properly
applied; for example, global style that dictates Verdana font
family is properly overridden by the style applied to a
Panel or its child.
From the designer of an enterprise framework perspective, this
means that if you create a base class for the styles, and some time
later, decide to change it, the change may affect all derived
classes. Suppose you subclassed ComboBox and defined some new styles in derived
MyComboBox and then later you change
the style of the ComboBox. For the
descendent class this means that now code changes are required to
properly (according to the changed rules) apply the overridden and
added styles.
All this explains, why every book and product manual keeps
warning that styles are expensive and you should limit the use of
the setSyle() function during the
runtime. With properties, life is a lot easier.
A beneficial framework would allow application programmers to define a small named set of application-specific styles and properties and the ability to govern the work of the UI control with selectors.
To accomplish this, get into the DataGrid state of mind
Have you ever thought of how a DataGridColumn object sets its own width, height
and other values? The DataGridColumn
class is a descendent of a style selector called CSSStyleSelector, which means it can be used to
modify styles but not properties.
DataGrid examines every
DataGridColumn and asks itself, "Do I
have the same as this column object in my cache?" If it does not,
it answers, "Nope, there's nothing I can reuse. I need to create a
new class factory to supply a new item renderer." After this is
done, the DataGrid code assigns the
supplied DataGridColumn to item
renderer as a style. (Search for renderer.styleName=c in the code of DataGridBase.as to see for yourself. )
At this point, all the specified column's styles (height, width,
color, text alignment) are applied as styles to the item
renderer.
Treat DataGridColumn as a CSS style
selector that also includes a limited number of properties (i.e.
itemRenderer). DataGrid creates on instance of such selector
object and then re-applies it to ever cell in this column.
Unfortunately, designing a DataGrid
this way makes it next to impossible to externalize this CSS style
selector, and you can't extend the properties of the data grid
column to make them specific to the item renderer. Say, you wanted
to use a CheckBox with a property
value (on/off) as an item renderer.
Tough luck – DataGridColumn is
not a dynamic object and you can't just add this as a new
property.
Flex is an extendable framework, however, and what you
can add is a new resource
class with behaviors more to your liking. In fact, that's exactly
what the ResourceBase class does, and
it's described next.
Continue to Part 2 of this chapter.









Facebook Application Development
Oops. Your HTMLs are showing :)
Can not understand the lay out . Also the code editor was so terrible that we even could see HTML tags like "span". God , please save me
Hey guys, thanks for catching this. Obviously, the producer (me!) wasn't paying enough attention when prepping this excerpt. The extraneous tags have been removed.
There's more cleanup to be done. All < and > have to be replaced with correspondingly.
Sorry about that, our code formatting seems to have gotten things backward here. This is fixed now also.
Almost there :)
The escaped minus sign seems to be the last thing to fix (just search for the word minus).
"and you can simply set textAlign=true on DataGridColumn." seems to be "and you can simply set textAlign=center on DataGridColumn."
and
var val:String; val= 'Texas' ;
for (var i: int = 0; i if ( val == cbx_states.dataProvider[i].label) {
cbx_states.selectedIndex = i;
break;
}
}
=>
var val:String; val= 'Texas' ;
for (var i: int = 0; i if ( val == cbx_states.dataProvider[i][labelField]) {
cbx_states.selectedIndex = i;
break;
}
}
"We're only human,
Born to make mistakes....!"