Archive for March, 2007

Thinking About Item Renderers

Many Flex apps have DataGrids. Many of those DataGrids want to display something other than plain text which requires the use of custom item renderers. I’ve seen lots of questions and complaining about how hard it is to make simple custom item renderers. I didn’t design it to be that hard, so I decided to take some time and make some examples of how I’d do it to serve as a starting point for some of the things you want to do in DataGrids.
I found the difficulty level to be about what I expected, but along the way I reminded myself of somethings you might find useful when making your own item renderers. What follows are those things you should probably know, and then some examples.
Recycling
Custom Item Renderers does take a mental shift from other kinds of UI development in Flex. This is because item renderers need to be completely data-driven, and because they are not mapped to the dataprovider in a one-to-one fashion. A single instance of an item renderer can end up displaying the data of several different items in your data provider. It might display the first item, then the tenth, then the second as you scroll up and down in the DataGrid. We do this for efficiency reasons: if we made a renderer for every item in the data provider it would consume tons of memory. Therefore we only create item renderers that are visible, plus a few others for measurement and buffering. This has the following implications:
You cannot assume the renderer has been freshly created. When it is time to update the renderer, the components might be holding old values from the item it was rendering before.
You cannot assume that there are only as many renderers created as you see on-screen.
You cannot assume that the first renderer created is for the first visible row.
The most common error I’ve seen is in not resetting values. For example, if you have code that makes the text red if the value is below zero, you might write:

if (data.price < 0)
setStyle("color", 0xFF0000);

This is incorrect. It will work the first time the renderer is created since the default color is black and will work if values are greater than 0, and if the value is less than zero. But once the renderer displays a value less than zero and turns the text red, if it is later asked to renderer a different value that is greater than zero, there is no code to turn the color back to black again. What will happen is that the data will look fine until you start scrolling or receiving updates, then the red will start to appear in funny places. The correct way is to write code like this:

if (data.price < 0)
setStyle("color", 0xFF0000);
else
setStyle("color", 0x000000);

That code will reset the color to black if the price is greater than 0.
Performance
When designing custom item renderers, you should keep performance in mind. While it is simple and fast to take a Canvas, HBox or VBox and put a few components in there and have a renderer, keep in mind that containers are really big and slow and if you are going to have lots of them visible in your DataGrid, you might run into performance problems. We often don’t see them because we develop on really fast machines, but you have to consider what kind of hardware your end-user will have. So, I’d discourage the use of any container from mx.containers in a custom item renderer if there’s going to be more than a half-dozen on screen. Unless you are laying out more than three or four widgets in your renderer, it will be much faster to start with UIComponent and just write some logic to layout the components in their correct positions. Containers from mx.containers also factor in deferred instantiation logic, scrollbars, clipping and a bunch of other things that your probably don’t need to use in your renderer.
That’s why you’ll see that all of the examples use ActionScript instead of MXML. Yes, that means that you can’t use FlexBuilder to code the renderer, and yes, some of these examples could be done in MXML, but it is easy in MXML to do things that generate extra code that you may not need. You’ll notice that I do not use databinding in these examples for the same reason. It is actually a bit wasteful (although very convenient) to use binding on something that isn’t going to change or only change once or twice. Instead, I set the dataprovider on the initialize event (and would do so on a result event if I used HTTPService).
Events
One frequent complaint is that, if your renderer dispatches events, it is hard to find a way to listen to those events. This is true to a degree. We sort of figured that 80% of renderers would be passive. I’m now thinking that number is closer to 50%. However, it isn’t really that hard to get events, or even to be able to hook up to those events in MXML. First, you need Flex 2.0.1 or later. While some have suggested that you use event bubbling to get events out of the DataGrid, I think that’s potentially unscalable. If you don’t guarantee that the event has a unique name, there could be some parent container of DataGrid that uses the same event name and you’ll get runtime errors. Instead, simply dispatch an event from the owner as in:

var event:Event = new ListEvent("myCustomEventName");
event.itemRenderer = this;
owner.dispatchEvent(event);

This event is then dispatched from the DataGrid, and has a reference to the renderer (and therefore the data) that was affected. To write a handler in MXML, you simply have to subclass DataGrid and add event metadata as in:

/**
* Broadcast when the user does something in the item renderer
*/
[Event("myCustomEventName")]
/**
*  Subclass of DataGrid that dispatches a custom event.
*/
public class MyDataGrid extends DataGrid ...
...

DataGridColumns
However, I want to introduce another way of handling events, and that is to use custom DataGridColumns. The DataGridColumn can act as a proxy for item renderers allowing maximum reuse by allowing the specification of parameters on the column that the renderers respond to, and by being a place to listen to for events from the columns. You’ll see many of these examples use subclasses of DataGridColumn that are paired with the custom renderer. One example, the ComboBoxHeader example, uses custom events from the DataGridColumn instead of through the DataGrid.
DataProviders and Collections
It is also possible to write custom DataProviders/Collections. You don’t have to work just with Arrays or XMLLists. The example NameValueTable takes a data object and displays it in a DataGrid by using a custom collection to enumerate the properties based on a ordered list of properties for the data object.
The Examples
These examples come with the usual caveats. They are unsupported, might have bugs, might not work in your app. Also note that future releases of Flex will likely have more powerful DataGrid features built-in. However, if you can’t wait, maybe these examples will help.
BackgroundColor in Item Renderers
Background Color Demo
Background Color Source
While you can use a Canvas and the backgroundColor style to do this, it turns out that the default DataGridItemRenderer is based on TextField and TextField can have solid color backgrounds. This example has a custom DataGridColumn that allows customization of the background color and value as to when display the colored background.
BackgroundColor Changes When Data Changes
Blink When Data Changes Demo
Blink When Data Changes Source
This example is a variation of the BackgroundColor example where the background color is only shown briefly if the data in the renderer changes.
Text Color and Styles in Item Renderers
Text Styles Demo
Text Styles Source
This example changes the color of the text and makes the text bold based on criteria in a styleFunction that works like labelFunction. By specifying different styleFunctions you can get the color and other font styles to be different based on the data.
HTML in an Item Renderer
HTML Renderer Demo
HTML Renderer Source
I’ve seen many people use the Text component as a renderer for rendering HTML (the subset of HTML that Flash supports, that is). It turns out that the default DataGridItemRenderer can handle HTML with a few minor tweaks and is lighterweight than Text.
Sub-Object Item Renderers
Sub-Object Demo
Sub-Object Source
The default DataGridColumn only handles properties on the dataProvider items. It doesn’t know how to look “deeper” for properties in the items’ sub-objects. That’s for performance reasons. Normally, we tell you to use labelFunction, which is a fine solution, but this example shows how a custom DataGridColumn and custom item renderer can also take the extra time to look at sub-objects.
Split Columns/Grouped Columns
Split Column Demo
Split Column Source
Several folks want to see a column split in two with a header over the two columns. Again, this can be done via custom DataGridColumns and custom item renderers. This example allows you to specify two custom sub-DataGridColumns that define the renderers for the sub-columns.
Custom Header Renderers (CheckBox)
CheckBox Header Renderer Demo
CheckBox Header Renderer Source
Making custom header renderers is a bit trickier, especially if they are interactive. You might need to disable certain default behavior in the DataGrid. This example shows how to get a CheckBox as the header for the column.
Custom Header Renderers (ComboBox)
ComboBox Header Demo
ComboBox Header Renderer Source
Another classic custom header is a ComboBox that allows you to pick filters for the DataGrid data. This example uses a custom ComboBox that allows specification of separators in the list of items, to mimic the look some people use in Excel. This example dispatches a custom event via the custom DataGridColumn.
List of CheckBoxes
CheckBox List Demo
CheckBox List Source
This doesn’t use DataGrid, but I put it here to show one way to do this. It uses an inline item renderer to modify the data provider directly. It is tempting to use rendererIsEditor for this functionality, but it feels better if you handle the change event directly instead of relying on the editable renderer workflow which doesn’t update the data provider until after you click out of the renderer.
Name Value Table/Custom Collection
Custom Collection Demo
Custom Collection Source
.
This also doesn’t use DataGrid, but is a good example of how to build a custom collection. In theory, a custom collection could insert groupings into the array of email much like Outlook does. Maybe I’ll prove that in an example some day, but future releases of Flex should have this functionality built-in, and there are some good versions from third-parties already. I put up this example to get you to consider using custom collections to solve some of your problems
Someday there will be other examples available as well (maybe).. Hope these help.
-Alex

SWF is not a loadable Module

Did you get this error using modules? This error means that you tried to load the module from a different server than the one the loader is running on, and/or you don’t have crossdomain.xml permission to load the module from that server.
Flash/Flex has a lot of security built in so that mean people can’t use Flash/Flex to do mean things to other servers. All SWFs therefore belong to the domain of the server where that SWF lives.
For example, if we’re running a SWF that lives at http://a.b.com/main.SWF, that SWF belongs to the domain “a.b.com”. If you try to load a SWF from somewhere else, such as http://c.b.com/module.SWF or http://e.f.org/module.SWF, then you are loading across domains.
The Flash Player will then look in the root directory of c.b.com or e.f.org for a file called crossdomain.xml, and see if a.b.com is listed in that file (or the file lists ‘*” which means “everybody”). If not, you cannot load the SWF as a module because, due to other security restrictions in the Flash Player, SWF loaded from another domain without crossdomain.xml permission go in a separate SecurityDomain, which means that it will have its own ApplicationDomain which means it cannot share classes with the main SWF and thus the ModuleManager can’t see the objects in the SWF as Modules.
Because this is a security-related issue, there are no real workarounds. You either have to make sure that your modules are in the same domain as the SWFs that load them, or you have to set up crossdomain.xml files so they can be used from SWFs in other domains. If you are trying to use a third-party module, you probably don’t have access to the third-party’s server and thus can’t add yourself as an accepted domain in their crossdomain.xml file. That’s annoying, but those are the rules. Server owners must either give explicit permission or decide to openly share SWFs resources on a server by listing your domain in crossdomain.xml or using ‘*”.

ArrayCollection, Arrays and Server Data

I call this the “array of one” problem. I make a request to the server for some data, usually a list of things, and it comes back and I stuff it in a dataprovider and it displays just fine….sometimes. Sometimes I get an error about converting/coercing ObjectProxy into an Array or ArrayCollection. After further investigation it turns out that it is only if the list of things has zero or one items that I get the error.
This is an unfortunate fact-of-life when serializing objects as xml. XML is really just formatted text, so all type information is essentially lost. We don’t know if the data is a String, Number, Array or Object and end up making a good guess.
For example, if I have the following data to send:
class Employee
{
var Name:String = “Alex”;
var EmployeeID:Number = 123;
}
It gets serialized as a one string
“Alex123″
On the receiving side, the code sees that there isn’t anything numeric about “Alex” so it leaves it as a string, and that “123″ is all digits so it parses it as a Number.
Now if the data is a list of values such as
class Manager
{
var Manager:String = “Steve”;
var DirectReportEmployeeIDs:Array = [123, 456, 789];
}
That might get serialized as:
Steve123456789
On the receiving side, the code sees that there are multiple so it decides to make an Array of those values.
Now if there is only one direct report, the data is going to come over as:
Steve123
and sure enough, it no longer looks like an array, does it? That’s why this is the “array of one” problem.
So, how to deal with it? There is no single right answer. There are type-preserving serialization technologies but they aren’t as popular. You can just check to see if the thing you think is an Array or ArrayCollection is, and if not, convert it to an array by pushing onto a new array, or you can work with the data as XML and use XMLListCollection which will see the “array of one” as an XMLList.
To check, you would add code like:
if (event.result is ObjectProxy)
list.dataProvider = [ event.result ]; // short cut for new array()
else
list.dataProvider = event.result.
To use XML and XMLListCollection, set the resultFormat=”e4x”.

Garbage Collection and Memory Leaks

I’ve seen lots of hair-pulling and confusion over memory management and garbage collection in Flex and Flash. Memory diagnostic tools are on the way, but until then, determining if you have a memory leak is a difficult thing to do. The attached presentation attempts to provide a simplified model of how the Flash Player manages memory. Hopefully, once you get a better understanding, it will save you time and hassle trying to detect memory leaks in your applications.
Download Presentation
I also put together a sample app that has a straightforward memory leak that hopefully will serve as an example of how I diagose memory leaks in Flex 2x. The tools in the next release will make this much easier, but the technique used here has served me well.
Download Sample

Embedded Fonts in Modules

A question was asked on Flexcoders about how to use embedded fonts in modules and late-load the embedded font. This example, inspired by Jonas.Eliasson, shows how it can be done.
Note that this example expects you to have an assets folder with arial.ttf and arialbd.ttf which I did not put in the zip because most of you have it somewhere, and I think it may be illegal to ship a .ttf across state lines.
Download file

Modules

I put together this presentation for the 360 Flex conference in San Jose. Thank you to those who attended and filled up the room so I could impress my manager with my supposed popularity.
The presentation contains a basic introduction to modules and how to use them, and an attempt to explain ApplicationDomains which are an important factor in how modules and RSLs (Runtime Shared Libraries) work.
The presentation is here: Download file
And some sample code is here: Download file
The sample code has build.script files that require a unix shell and show how some of the MXMLC parameters are used. (The usual caveats, disclaimers, and other legal stuff apply).
Enjoy!

Welcome

Welcome. I finally got motivated to join the rest of the world and start a blog. This one is all about Flex-related things. I’ve been developing components for Flash and Flex for almost five years. My main areas of expertise are the UI-related code, most of the manager classes, and things related to loading swfs.
My goal is to put things on here related to things that I hear asked often, and maybe some half-baked things as well. We’ll see how often I can get over here.