This application demonstrates the problem with the default ItemRenderer behavior when using view states within an item renderer. In the example on the left the added content disappears as soon as you mouse out of the expanded cell. The example on the right overrides getCurrentRendererState to prevent that. Right-click the app to view source or download an FXP file here.

One of the things that makes Flex so attractive is the extensive set of default behaviors provided in its many controls. Sometimes, however, that default behavior is not what you want and you have to work with Flex to get your desired behavior. I ran into a case of that recently when working with a DataGroup.

I created an ItemRenderer which contained a button the user could click to expand the cell to provide some additional information about the product in that cell. That worked fine but I discovered that the DataGrid row collapsed back to its original size as soon as I moved the mouse out of that cell. The problem is that the Flex ItemRenderer base class includes some default behaviors for mouse over events (among others). For mouse over, the current cell is highlighted and, of course, for mouse out the highlight is removed. This was fine but, in my case, the problem was that when I moused out, the ItemRenderer reverted to its normal state—which was the state without the added content. Here’s my original item renderer:

<?xml version="1.0" encoding="utf-8"?>
<s:ItemRenderer xmlns:fx="http://ns.adobe.com/mxml/2009" 
				xmlns:s="library://ns.adobe.com/flex/spark" 
				xmlns:mx="library://ns.adobe.com/flex/mx" 
				autoDrawBackground="true">
 
	<s:states>
		<s:State name="normal" />
		<s:State name="details" />
	</s:states>
 
	<s:Rect height="100%" width="100%">
		<s:stroke>
			<s:SolidColorStroke color="black"/>
		</s:stroke>
	</s:Rect>
	<s:VGroup paddingTop="10" paddingLeft="10" paddingBottom="10" paddingRight="10">
		<s:Label text="Always Displayed" includeIn="normal, details"/>
		<s:Label text="{data}"/>
		<s:Group>
			<s:Button label="Add 2nd label" includeIn="normal" click="currentState='details'" />
			<s:Button label="Remove 2nd label" includeIn="details" click="currentState='normal'"/>
		</s:Group>
		<s:Label text="Detailed description" includeIn="details"/>
	</s:VGroup>
</s:ItemRenderer>

There are two states, “normal” which is the original state without the “Detailed description” label, and “details” which does include this label. There is also a pair of buttons to allow the user to show and hide the detailed description label. Only one of those buttons is shown at any given time based on the value of currentState.

The solution I found was to override the ItemRenderer method getCurrentRendererState. I also added two states, including the hovered state which the Flex ItemRenderer base class implements:

<s:states>
    <s:State name="normal" />
    <s:State name="hovered" />
    <s:State name="details" />
    <s:State name="hoveredDetails"/>
</s:states>

I modified my item renderer to apply the new states appropriately:

<s:VGroup paddingTop="10" paddingLeft="10" paddingBottom="10" paddingRight="10">
    <s:Label text="Always Displayed" includeIn="normal, hovered, details, hoveredDetails"/>
    <s:Label text="{data}" includeIn="normal, hovered, details, hoveredDetails"/>
    <s:Group>
        <s:Button label="Add 2nd label" includeIn="normal, hovered" click="currentState='details'" />
        <s:Button label="Remove 2nd label" includeIn="details, hoveredDetails" click="currentState='normal'"/>
    </s:Group>
    <s:Label text="Detailed description" includeIn="details, hoveredDetails"/>
</s:VGroup>

And I implemented my override of getCurrentRendererState:

protected override function getCurrentRendererState():String
{
    var newRenderState:String = super.getCurrentRendererState();
    if((currentState == "details" || currentState == "hoveredDetails") && newRenderState == "normal")
    {
        newRenderState = "details";
    }
    if(currentState == "details" && newRenderState == "hovered")
    {
        newRenderState = "hoveredDetails"; 
    }
    return newRenderState;
}

Here, I force the state to include the details even when the user mouses out and, in so doing, get the desired behavior.

Download sample project (FXP).

{ 2 comments }

In my past three posts I’ve been evolving a technique for creating a type-safe collection class that can be used a DataProvider for Flex Lists and DataGrids. As I’ve discussed previously, the problem with these controls is that they use the ArrayList or ArrayCollection classes as their data providers. And the problem those collections is that they are not type-safe. You can put any type of object into an ArrayList or ArrayCollection. That’s not a problem until you put the wrong type into one. Then, you get an error at run-time. It would, of course, be far better to catch the error at compile time. In this post I present the culmination of my technique which makes it convenient to use a type-safe container with Flex Lists and DataGrids.

This application wraps an instance of Vector.<Person> in a class to provide type-safe access. This class implements IList so that Lists and DataGrids can use it as a DataProvider. Right-click the app to view source or download an FXP file here.

Having honed the technique over the course of four blog posts I’m now making available a TypeSafeList abstract class which you can easily and quickly extend. With only about 20 lines of code you can create a subclass of TypeSafeList that will contain any single data type of your choice. Any attempt to insert an object of the wrong type will be caught at compile time. And, because TypeSafeList implements IList your subclass can still be used as a data provider for Lists and DataGrids.

If you want to know how the technique works, see my previous posts:

  1. Type-Safe DataProviders for Flex Lists with the ActionScript Vector
  2. An Enhanced Type-Safe Data Provider Technique for Flex IList-Based Controls
  3. Type-Safe DataProvider for Flex DataGrid; Data Loading Encapsulated w/Parsley DynamicCommand

If you just want to use TypeSafeList to quickly create your own type-safe collection classes you can skip the previous posts and just read this one.

To use TypeSafeList you need to create a container class that extends TypeSafeList and has a Vector as an instance variable. You should, of course, type the Vector to contain the object type that you’re interested in. For this example, we’re going store Person objects so we’ll have:

private var _people:Vector.<Person>;

Next, you need to define a type-safe interface for accessing your Vector. Here’s a minimal example:

public interface IPersonVectorDP
{
    function pop():Person;
    function push(value:Person):uint;
}

You can name your interface whatever you like; here, I’ve used IPersonVectorDP. You will add or remove Person objects to _people only through this interface. Your interface could have other methods; e.g., insertItemAt or deleteItemAt (note that you must not use any of the same method names as the IList methods). Whatever methods you define in your interface will need to be implemented in your type-safe collection’s implementation class.

Here’s the beginning of an example TypeSafeList subclass with our _people Vector:

public class PersonVectorDP extends TypeSafeList implements IPersonVectorDP
{
    private var _people:Vector.<Person>;
 
    public function PersonVectorDP()
    {
        _people = new Vector.<Person>;
    }
    .
    .
    .

Next, we implement the methods in our IPersonVectorDP  interface that we defined above. Here, we implement the push and pop methods we declared in IPersonVectorDP:

public function push(value:Person):uint
{
    var count:uint = _people.push(value);
    dispatchAddEvent(value, count);
    return count;
}
 
public function pop():Person
{
    var poppedPerson:Person = _people.pop();
    dispatchRemoveEvent(poppedPerson, _people.length);
    return poppedPerson;
}

These methods wrap Vector’s push and pop methods. In addition, they call event dispatchers in the TypeSafeList superclass. These event dispatchers notify the Flex List/DataGrid controls when the container’s elements have changed so that the controls can update their views of those elements.

At this point, you need to write a function to provide access to your Vector so that TypeSafeList can access elements as needed by Flex’s List & DataGrid controls (through IList). You have a choice between a clean, easy approach that can be wasteful of memory and an efficient approach which requires you to modify a few lines of code in TypeSafeList.

First, here’s the clean, easy approach. You define a function which returns a reference to your Vector as a Vector of Objects. In our example, we return a copy of the _people Vector.

override protected function getVector():Vector.<Object>
{
    var vector:Vector.<Object> = Vector.<Object>(_people);
    return vector;
}

This works fine for TypeSafeList because Objects are what IList uses. IList doesn’t need to know about Persons so neither does TypeSafeList.

The problem with this technique is that every time an element is added to your Vector a copy of the entire Vector is made in getVector. For small collections the overhead will be negligible. But for collections consisting of thousands of elements the overhead could be substantial. But without pointers (or pointers to references) as in C++ there’s nothing that can be done. Except to get in and muck around in the base class code.

So, here’s the efficient but slightly messy alternative: you edit a copy of TypeSafeList and modify the existing getVector function to return a Vector of your type. Here’s the stock getVector function from TypeSafeList:

protected function getVector():Vector.<Object>
{
    throw new IllegalOperationError("Error in TypeSafeList; you must subclass TypeSafeList and override getVector");
    return null;
}

And here’s a modified version:

override protected function getVector():Vector.<Person>
{
    throw new IllegalOperationError("Error in TypeSafeList; you must subclass TypeSafeList and override getVector");
return null;
 
}

Now, you can modify your override to return a Vector of your type; e.g.,

override protected function getVector():Vector.<Person>
{
    return _people;
}

You also need to make a couple more edits to TypeSafeList. First, there’s a Vector.<Object> declaration in getItemIndex; just change it to your type; e.g., Vector.<Person>. Second, there’s a loop in which an element var is declared:

var element:Object = vector[i];

You’ll also need to change the Object type to your type.

As you can see, there are actually only three lines of code to modify if you want to go the performance route. Unfortunately, that means you’ll need to create a separate copy of TypeSafeList for each data type you want to use it with. But until ActionScript has full support for generics this is the best we can do. But, at least, we can now have type-safe collections for use with Flex ListBase-derived controls and DataGrids.

Download the example project (FXP).

{ 1 comment }

Type-Safe DataProvider for Flex DataGrid; Data Loading Encapsulated w/Parsley DynamicCommand

March 7, 2011

In this post I’m continuing the theme of my last two posts, type-safe DataProviders, and combining it with the theme of the two posts before that: the Parsley application framework. I’ll be using Parsley’s DynamicCommand object to encapsulate the fetching of data from a server and then store it in a type-safe DataProvider that will [...]

Read the full article →

An Enhanced Type-Safe Data Provider Technique for Flex IList-Based Controls

February 26, 2011

Last week I posted an article showing how to create type-safe lists for use as Flex List-based DataProviders. This week I’m enhancing that example to dispatch events when items are added to or removed from the collection. This will allow Lists to update their displays automatically whenever the contents of the DataProvider change. If you [...]

Read the full article →

Type-Safe DataProviders for Flex Lists with the ActionScript Vector

February 21, 2011

Update, 2/25/11: I’ve updated the code to provide both complete type-safety and event dispatching so that Lists will update their views automatically when the list contents are changed. If you’re interested in this topic, you will probably still want to start by reading this post. But be sure to continue with my follow-up post An [...]

Read the full article →

Menu Tutorial Using the Flex Parsley Application Framework

February 7, 2011

Update 2/12/2011: Based on feedback from Jens, the creator of the Parsley framework, I’ve updated this post and the downloadable sample code. Last year I posted an example of a Flex sliding menu component along with a simple project that shows its use. Here, I present a variation of the menu using the Parsley application [...]

Read the full article →

Flex 4 Version of Art’s Flex Notes Project

February 5, 2011

Arturo Alvarado has a very nice series of tutorials on the Parsley application framework but they’re in Flex 3. A couple of them have been translated into Flex 4 by other blog readers but not the code for his Quick Dive into Parsley (Nested Contexts & Object lifecycle methods – Part 6). I’ve done that [...]

Read the full article →

Server-Side Validation with Flex

January 22, 2011

This application uses a custom Validator subclass which performs both client-side and server-side input validation. The client-side validation is done first whenever the First Name field loses focus. If it passes the client-side validation the input is sent to a server for further validation. Standard Flex Validator functionality is used. Right-click the app to view [...]

Read the full article →

Creating a Custom Animation Effect in Flex 4

December 19, 2010

As I discussed in my previous post “O’Reilly’s Flex 4 Cookbook Continues to Disappoint” I recently was frustrated when looking there for sample code to create a Flex 4 custom effect. The Adobe docs have some information on their page “About creating a custom effect” but some of the details are missing, particularly if you [...]

Read the full article →

O’Reilly’s Flex 4 Cookbook Continues to Disappoint

December 19, 2010

I’ve been a fan of the O’Reilly Cookbooks in the past and have found valuable info in both their ActionScript 3.0 Cookbook and Flex 3 Cookbook. So, when O’Reilly released their Flex 4 Cookbook earlier this year I purchased a PDF copy as soon as it became available. However, I’ve been disappointed by this volume [...]

Read the full article →