Optimizing the Flex Runtime

2011 January 10
by admin

Introduction

The Flex Framework provides a great platform for developing Rich Internet Applications. Some of the best features of the framework include the ability to automate code (MXML, Binding, States), the vector graphics support (FXG, GraphicElements, native graphics class), and the Rich component library. However, a lack of understanding of the Flash Player execution model, the flex component life cycle, or the vast component library (spark and halo) can lead to some extremely heavy run-time considerations. Furthermore, depending on the compiler to generate code can lead to heavier components and substantially larger swf sizes. This post is based on a number of articles and presentations that I have studied and will provide reference for at the end. However, it was based primarily on a presentation given by Ryan Frishberg at Adobe MAX. I recreated the Keynote as well as the examples within his presentation and have attached them to this blog post. This post is not meant to be exaustive or even touch on 1/2 of the ways you can optimize your applications. Rather, it should be thought of as a quick reference to broader topics with links to more in-depth studies on Optimization.

The Flash Player execution model

The first thing that I think every Flex/Flash developer should understand is how the Flash Player renders things. It uses the concept of frames to process ActionScript code and then update the visual appearance of the screen to the user (a default of 24 times per second in Flex). The use of frames allows developers to easily add fun effects and animations to any Application–one of the things that makes Flex so attractive. However, one of the things that few developers understand is that ActionScript is processed within a single frame unless otherwise specified. This means that complex ActionScript or Graphics manipulation will cause longer frame lags and result in a choppy or frozen visual display. Let’s analyze a diagram from Ted Patrick displaying this process a little better:

Image taken from http://www.craftymind.com/2008/04/18/updated-elastic-racetrack-for-flash-9-and-avm2/

Notice from the diagram that heavy code execution or graphical rendering will cause a frame to stretch out. Here are a few recommendations for optimizing the user experience by decreasing frame lags:

  • Don’t bloat the client with server side logic – There are a lot of things that belong on the server so that they don’t slow down the display. When people first start working in Flex they become excited about the object oriented nature of the language and the ability to do so many things. If people were working in an AJAX project, they would automatically put a lot of logic in the server because of the superior nature of server side language. Please resist the temptation to put complex computations in ActionScript and keep them where they belong.
  • Be aware of frame execution time – It is really important to know how much time you have to process your code and maintain a good user experience. The default frame rate within flex is 24 fps. This means that you have 40 milliseconds to process all of your code and change the display. If a process is going to take more time then try to split it up in more than one frame. This is a process called pseudo threading. In Flex, you can use the callLater() function to add logic to a queue that will be called within the next frame. To break logic up into multiple frames, you can create your own queue that is triggered on an Event.ENTER_FRAME event. For a good post on pseudo threading refer to Alex Harui’s comments at this link.

The Flex Component Life Cycle

Now that we have discussed the concept of frames within the Flash Player let’s dive into how they are used within Flex. The Component Life Cycle is a series of events and function calls made by the Flex Framework to ensure that logical chunks of data are processed synchronously and only once per frame. It uses validation triggers to call methods within each component in a continuous loop. A lack of understanding of the process can lead to validating a hierarchy of components multiple times per frame instead of just once. The ramifications of such an action can lead to heavy frames and an unpleasant user experience. Please refer to the table below for a brief list of the different functions in this process and what should be placed in them. Each method can be overridden by subclasses and modified as needed. NOTE: None of the methods should be called directly. Instead, the methods can be invoked by setting their setting their invalidation flags as specified.

Method Invoke Method Description
createChildren() Only called once This is the first method called in the flex event stack and is where you will want to add any children of the component. If you are using mxml this method will be automated by the compiler.
commitProperties() invalidateProperties() Commit Properties is called on creation, every time a new child is added, and when it is flagged with an invalidate method. You will want to override this method to set the properties of your DisplayObjects. If you set the properties of a Display Object directly (e.g. label.text) outside of commitProperties you may force validation to occur more than once.
measure() invalidateSize() If you have extended UIComponent then you will need to write your own measure function. However, if you are creating a component from another container, (e.g. HGroup) it will provide it’s own measuring. HINT: An easy way to measure your component is to set the measuredWidth and measuredHeight to the measuredWidths and measuredHeights of child components.
updateDisplayList() invalidateDisplayList() This is where you will move child components (set x and y coordinates) and draw anything to the stage. If you have extended UIComponent you will need to call setActualSize() on each component or they won’t show up.

Spark vs. Halo Components

The Spark Library was built with optimization in mind. We would see immediate performance gains by simply switching everything over to Spark because of the new modular design. For example, a spark Group is extremely light weight compared to a flex 3 Container because logical portions such as skinning, layout, and scroll bars can be added as needed instead of being inherited by default. When using a component, look first to the spark library to see if there is a matching spark component before defaulting to the Halo component.

Here are a couple other recommendations when using Spark components:

  • MX Navigator’s (e.g. ViewStack, TabNavigator, Accordion) only accept children of type INavigatorContent. The only container within the spark library that implements this interface is the NavigatorContent. Please use the NavigatorContent Container instead of defaulting to the old halo containers.
  • If you need to skin a container then use a container that extends from SkinnableContainerBase such as SkinnableContainer or SkinnableDataContainer. A Group does not support skinning in order to be as light as possible. If you do not need the skinning behavior then use a Group. Always use the lightest component possible.

Defer instantiation of components

When developing within the Flash Player we must be continuously mindful of Frames. Remember, we only have 40 milliseconds (in a 24 fps application) to render data to the screen. If we attempt to render too much at once, frames will be stretched out and our application will appear to be frozen to the user. I have seen some applications where progress bars will stop for 4 or more seconds to render all data to the screen. Using our image of the elastic racetrack, this would be the concept of Heavy Rendering. One of the best ways to mitigate the risk of “Heavy Rendering” is to minimize the amount of visual components added to the stage at one time. There are three ways to defer instantiation of components within flex:

  1. Use a Navigator Container – Navigator Containers such as ViewStack and TabNavigator have a property called creationPolicy that will add the children to the stage as necessary if set to true.
  2. Use states – States will only add components to the a container when and if the states are set. They will also remove those components when you exit that state. NOTE: states are just a way of automating ActionScript so you could easily provide this logic on your own.
  3. Write custom ActionScript – Use the addElement, addElementAt, removeElement, and removeElementAt methods to add and remove children via ActionScript as needed.

Utilize Virtual Layouts for large data sets

Another way to delay the instantiation of components is to use a Virtual Layout Container such as a List. In a Virtual Layout, only the visible components in a Viewport are created and then they are recycled as you scroll.  To use an example, lets assume that you wanted to create a Viewport with 1000 columns and 1000 rows.  If you tried to create each child in the ViewPort you would have to add 1,000,000 children (1000 * 1000) to the stage.  Obviously, this would have some extreme performance considerations in the Flash Player.  In fact, the Flash Player would probably crash or throw up an ActionScript error.  On the other hand, utilizing a Vitual Layout you would only create the visual children.  Please refer to the diagram below for a better depiction of this process.

Image taken from Ryan Frishberg’s Presentation

From the diagram above, the Viewport would only create 25 children at one time (5 * 5) instead of all million components.  It would then recycle the cells (ItemRenderer’s) as you scroll to the right or left.  The flex components that have been optimized with this virtual layout in mind include the following:

  • DataGroup – The lightest of all virtual containers. Does not support skinning, native hover states, or add the drag and drop functionality of a List. Should be used when you want to create a simple List or Grid of repeatable items.
  • SkinnableDataGroup – Exactly like DataGroup except that it supports skinning. Should be used to create simple Lists or Grids of repeatable items when a skin is needed.
  • List – Extends from SkinnableDataContainer and adds automatic hover and selected state indicators to items. Adds native drag and drop functionality without the need to add through code. Supports Data Virtualization by default. Should be used when extra functionality of the list will be used by child components.
  • DataGrid – Perfect for displaying complex data sets. Adds column headers, native item renderers, item editors, resizable columns, data virtualization, etc. This component is key to creating optimized data centric flex applications. As of flex sdk 4.5, there is a new spark DataGrid. If you are using 4.0 or 4.1 you will have to use the old halo DataGrid.

NOTE: DataGroup and SkinnableDataGroup do not support Virtualization by default. This needs to be added as an attribute of the layout object. In the following code example, notice the useVirtualLayout attribute:

1
2
3
4
5
<s:DataGroup itemRenderer="com.components.CustomRenderer" dataProvider="{myDataProvider}" width="100%">
     <s:layout>
          <s:VerticalLayout gap="0" useVirtualLayout="true" />
     </s:layout>
</s:DataGroup>

Optimize Custom ItemRenderer’s

Virtual Layouts alone will not create an optimized user experience. In fact, heavy or inefficient Item Renderers can create just the opposite. Remember the children (ItemRenerers) of a ViewPort are reused and reinitialized as you scroll. Therefore, inefficiency will cause a heavy user experience over and over as you scroll through the ViewPort. Here are some recommendations for overcoming common the most common problems:

  • Don’t use states – States are a great convenience to developers because they automate a lot of code and add a lot of logic to components. However, states also come with a cost as they add a ton of code. Please create your own state logic when possible within Item Renderers.
  • Stay away from Binding – Binding is another convenience within the Flex Framework that automates a lot of code. Behind the scenes, Binding is nothing more than an event protocol where event dispatchers and listeners are automated. This is a process that could add up to 2000 lines of code to a component for just one Binding. When inside an ItemRenderer please override the set data function instead of using Binding. For example:
    1
    2
    3
    4
    5
    override public function set data(value:Object):void
    {
         super.data = value;
         label.text = data.label;
    }
  • Use constraint and static layouts – One of the main ways that people create non-optimized code within ItemRenderer’s is by embedding a bunch of containers. For example, an HGroup with two VGroups (or HBox with two VBox’s) as children. A better practice is to use a Group (or SkinnableGroup) with a basic layout and either hard code x and y’s or use a constraint based layout. For more information on using constraint based layouts please refer to adobe’s site.
  • Use lightweight children – Finally, remember to always use the lightest children possible. For example, instead of using Image use BitmapImage. And instead of using RichText use Label. Obviously, there are cases where the heavier components are needed but use them sparingly.

Use FXG and Graphic Elements

In Flex 3, all children of a container had to be of type UIComponent. This Class provides a lot of the dynamic behaviors needed by custom classes within Flex. For example, it provides all methods of the component lifecycle as well as many properties shared among objects. However, for simple vector graphics classes, UIComponent is a lot heavier than needed. Flex 4 added the ability to add simple graphics known as FXG to containers that only have visual logic. FXG is an XML based markup that is very similar to SVG in syntax. It can be implemented either in MXML using the spark namespace or by generating an external XML file. Notice that FXG added through an external file is compiled in and cannot be changed at runtime. If you need to ability to change the graphic then it should be added through MXML. Also note that while you could hand write your own FXG, it is a lot easier to use an image manipulation tool like Illustrator to automate your FXG. In terms of weight, graphics should be used in the following order:

  1. FXG – External XML files. FXG is compiled into an application and cannot be changed at runtime
  2. Graphic Element (Runtime FXG) – Use FXG tags with spark namespace withing MXML. This is a little bit heavier than native FXG because of the runtime considerations.
  3. Custom Drawing with UIComponent – Extend from UIComponent and draw graphics using ActionScript when you need custom interactions. For example, if you need Roll-over or roll out states.

Other Performance Considerations

Here is are some other quick performance tricks–some of which came came straight from Ryan Frishberg’s presentation:

  • ArrayList vs ArrayCollection – An ArrayList is lighter (the parent of) than an ArrayCollection. You should use it as the source of a List or DataGrid when you don’t need sorting or filtering capabilities.
  • Resetting an Array – Creating a new Array in memory is a lot more expensive than resetting the array. Instead of using the syntax:
    1
            arr1 = new Array();

    use this syntax

    1
           arr1.length = 0;
  • Deep Cloning – There isn’t always a need to deep clone an object and especially not an ArrayCollection. The last place that I worked had a really bad practice of deep cloning every array to ensure that one view wouldn’t mess up the other view. An ArrayCollection is simply a wrapper for an Array Object. Therefore, making changes to one ArrayCollection (e.g. filter or sort function) won’t mess up the other ArrayCollection. You can create a shallow clone of an object by using the following code:
    1
         var newAC:ArrayCollection = new ArrayCollection( oldAC.source );

    Notice that the underlying source array stays the same. Filters and sort functions will be applied to the wrapper and not the underlying source. Therefore, they can be completely different. You may want to deep clone if the properties of the child objects will be changed.

Resources

Performance Tips and Tricks for Flex and Flash Development
Ryan Frishberg’s Keynote (Re-created from max video)
Flash Elastic Racetrack
Flash Player Garbage Collection
Flex Component Development
Deep Dive into Flash Player Rendering

ActionScript – Deep Copy Custom Objects

2010 December 29
Comments Off
by admin

Those that have been around Flex / Flash for a while have probably had the need to create a completely new Object out of an existing object. A common way to copy an Object is to instantiate a new Object and then copy over the properties individually. For example, if you wanted to copy a Person object it might look something like this:

1
2
3
4
5
6
7
private function clonePerson( personToCopy:Person ) : Person
{
      var newPerson:Person = new Person();
      newPerson.firstName = personToCopy.firstName;
      newPerson.lastName = personToCopy.lastName;
      return newPerson;
}

The problem is that most projects have multiple different Custom Objects (e.g. Person, Animal, Reptile) so the code above would need to be repeated for each Object. This process could be greatly streamlined by a more generic function that could copy any object. In the Flex world, you can use the ObjectUtil.copy() method to create a deep copy of an Object. For those using Flash, you can provide the same functionality by creating a function like the following:

1
2
3
4
5
6
7
private function clone( objToCopy:Object ):Object
{
     var ba:ByteArray = new ByteArray();
     ba.writeObject( objToCopy );
     ba.position = 0;
     return ba.readObject();
}

The ObjectUtil.copy() method creates a true copy of the Object in memory but does not maintain the Object type for Custom Objects. To get around this, I have always created my own clone method when I needed to maintain object types. Recently, I read a chapter in the Flex Cookbook that describes how to use the method above and still maintain an Objects type.

In the code above, an object is converted into a ByteArray (serialized as AMF or ActionScript Message Format) and then written out to a new Object. This is exactly what happens when an Object is sent across the wire as a Remote Object. An Object can be deserialized as long as the type is registered with the Flash Player ahead of time. This can be done by calling the flash.net.registerClassAlias() method. This method accepts two parameters:

  • aliasName – The fully qualified class name. e.g. “com.bradley.Person”
  • classObject – An Object of Type Class.

Because we want to make this function as generic as possible we won’t know what either of the above arguments will be. However, there are two methods within the flash.utils library that can provide those arguments:

  • flash.utils.getQualifiedClassName() – returns the fully qualified class name of an object passed to it.
  • flash.utils.getDefinitionByName() – returns a reference to the class object you passed into it.

Therefore, you could create a method such as the following to copy an Object of any type. NOTE: This function example was taken directly from the Flex Cookbook on page 346.

1
2
3
4
5
6
7
8
9
private function copyOverObject (objToCopy:Object, registerAlias:Boolean = false):Object
{
     if (registerAlias)
     {
          var className:String = flash.utils.getQualifiedClassName(objToCopy);
          flash.net.registerClassAlias(className, (flash.utils.getDefinitionByName(className) as Class));
     }
     return mx.utils.ObjectUtil.copy(objToCopy);
}

Flex 4 Containers – Modular Design

2010 November 15
Comments Off
by admin

One of the biggest mental paradigms to understand in flex 4 is the new modular design of components. In flex 3, a component did everything from drawing out graphics to laying out children to providing and managing it’s own scroll bars. This type of design conveniently allows you to customize design, layout, and anything else by modifying just one class. Unfortunately, it can also cause a lot of heavy logic to be added to simple components.

I recently started a contract with 20 Java developers transitioning to Flex. Their nativity has led to some very heavy run-time considerations. For example, I have looked through multiple classes where developers have embedded containers multiple levels deep. Some classes have more than 8 embedded VBoxes and HBoxes. Obvsiously, this is just a bad way to program using both flex 3 and flex 4 components. However, the performance of lighter more modular containers would be a lot better than containers where everything is inherited.

In flex 4, the components are a lot more granular and broken down into more logical chunks. The base spark container (Group) is extremely light weight. It does not manage it’s own layout, graphics, skins, etc. Instead, it uses different modules as necessary to perform logical tasks. For example, to add a scroll bar to a Group you have to either wrap a group in a Scroller or add a Scroller as a child of the group. Likewise, the layout of a group is managed by a layout class. This means that you no longer get base functionality of a Container or component for free but you add it as necessary.

I have heard many people say that they dislike the new design of spark containers. They complain about losing the convenience of controlling everything with a single class. While we have lost some convenience, we have gained a lot of control and embraced a more object oriented design. Spark components are not difficult to understand, they are just different. Let’s embrace the new design and go forward.

Transitioning to Flex 4

2010 November 15
Comments Off
by admin

What does it mean to switch to flex 4? It seems like every large enterprise is attempting to make the switch by changing their compile environments to the flex 4 SDK. I’ve personally been a part of 3 large projects that have supposedly “switched” to flex 4. However, after changing name spaces, and pointing to the 2009 mx component set, it’s been flex 3 programming as usual.  I’m ashamed to say that I have personally continued to use flex 3 containers and components because I know them inside and out.  I simply haven’t taken the time to get to know the spark component set.

Over the next couple of months, I will be diving deep into flex 4 (spark) by studying various oreilly books, reading through blog posts, creating and looking through code samples, and finally becoming flex 4 certified.  I plan to grow in understanding of the following:

  1. The new modular design of spark
  2. How / When to use the new spark containers
  3. Performance Optimization
  4. Skinning and FXG
  5. The Text Layout Framework (TLF)
  6. Flex 4 states (This includes performance optimization)
  7. Transitions between states
  8. Using Tweener and TweenLite with states
  9. The new classes for mobile development

I will be submitting incremental updates as I go through this journey so stay tuned.

Item Renderers and Flex

2010 October 6
by admin

I want to say thanks for everybody that participated in out lunch in learn for ItemRenders. Here is a summary of the items discussed in today’s meeting:

  • An Item Renderer is simply a component or a separate Class that can be created in-line (same mxml file) and externally through either an mxml or ActionScript file.
  • There are multiple components that use ItemRenderers including all ListBase Classes (Lists, Trees, DataGrids, TileList), Repeaters, and DataGroups.
  • ItemRenderers were written as a way of optimizing code by only building the viewable elements and then recycling those elements.
  • Because an ItemRenderer is reused it will only be created once.  Therefore, listening for a creationComplete event will only instantiate the component with the initial data.  The best practice is to override set data as you don’t know where or when it will be called.
  • Don’t ever try to access child item renderers from a parent.  This completely violates the flex framework.  Instead, let the child control itself.
  • To get from a child to a parent use outerDocument.function() for inline ItemRenderers and event bubbling for External ItemRenderers
  • Finally, for smaller data sets you can use a DataGroup

Here is the source code and the PowerPoint for the presentation that I gave today.

Project zip
PowerPoint

You can also see a live demonstration of the code by going to bradrogers.net/itemrenderers.  I will plan to keep the source code at this url for at least a year.  To view the source code just right click and select “View Source”.

I would also recommend going through this tutorial for a more detailed explanation of itemRenderers

Integrate mx RichTextEditor with spark RichText

2010 September 28
Comments Off
by admin

One of the greatest things about Flex 4 is the new TLF text layout controls. It is amazing how much more control they give you over the flow and layout of the text. It’s also great to be able to add animation or rotation to the text components without having to perform some sort of Bitmap hack like you had to in Flex 3. However, there is currently no flex 4 (spark) RichTextEditor to integrate with these components.

I looked online in hopes to find an out of the box solution that I could use similar to the mx RichTextEditor. Although I found a lot of great examples, none of them worked as seamlessly as the mx RichTextEditor that was already provided by adobe. I didn’t have the time to mess with someone else’s RichTextEditor or even write my own. So I decided to try to integrate the mx RichTextEditor with the new TLF Classes. As it turns out there is a TextConverter class that can be used to do exactly what I wanted.

Here is an example for how to convert the htmlText from a RichTextEditor to a textFlow element:

1
2
3
4
var txt:RichText;
var rte:RichTextEditor;

txt.textFlow = TextConverter.importToFlow(rte.htmlText, TextConverter.TEXT_FIELD_HTML_FORMAT);

(ActionScript) Loop through the properties of an Object

2010 September 28
by admin

In an ideal world we would we wouldn’t have to guess what is inside an object. I always try to make sure that I either create custom objects or define the object through notes within the code. However, in the last year I’ve worked on numerous projects where I’ve either picked up someone else’s code, tied into an existing backend, or used an external library (swc) thats passes me back generic objects. Throughout this experience, I’ve run into multiple instances where I haven’t been completely sure of the properties of any given data object. Although it’s fairly simple to loop through the properties of an object, I find myself googling how to do it every time. I wanted to provide a simple example so that I can have it for my own reference and hope that it will help anyone else that runs into the same problem.

1
2
3
4
for (var key:String in obj)
{
     trace("key: " + key + " value: " + obj[key]);
}

Creating ActionScript List Item Renderers

2010 April 16
Comments Off
by admin

One of the greatest things about Lists, among other flex components, is that they are so easy to modify through the use of ItemRenderer’s. An ItemRenderer can be very simple or very complex. For static lists, (those w/o drag and drop) it really doesn’t matter how complex the item renderer. However, when drag and drop is enabled a complex list can bring your browser or computer to a crawl. For this reason, I have sought to extend UIComponent and write my own ActionScript (as opposed to using mxml generated AS) to keep complex ItemRenderer’s as small as possible.

For an ItemRenderer to function properly you need to implement the following interfaces:

  • mx.controls.listClasses.IListItemRenderer
  • mx.controls.listClasses.IDropInListItemRenderer
  • mx.core.IFontContextComponent
  • mx.core.IDataRenderer

NOTE: If you extend a flex container (Canvas, Panel, VBox, HBox, etc) they already implement these interfaces.

After implementing the above interfaces and applying the appropriate method signatures, an item renderer is just like creating any other custom flex component. For those that have never created a custom flex component I have provided a brief list below of UIComponent methods that must be overriden when creating a CustomComponent. Please read the descriptions next to the functions and notice how to call them through various invalidate methods.

createChildren() This is the first method called in the flex event stack and is where you will want to add any children of the component.
commitProperties() Commit Properties is called every time add child is called. You may want to override this method to set the properties of your display objects. This function should never be called directly. You can trigger flex to call it by calling invalidateProperties(). Hint: You can access the properties of the item being displayed through the data property.
measure() If you have extended UIComponent then you will need to write your own measure function. Otherwise, the item renderer will only be visible if it is set to a static width and height. You never want to call measure directly. Instead call invalidateSize() and flex will call this function on the next refresh. HINT: An easy way to measure your component is to set the measuredWidth and measuredHeight to the measuredWidths and measuredHeights of child components.
updateDisplayList() This is where you will move child components (set x and y coordinates) and draw anything to the stage. You never want to call this method directly. You can call it indirectly by calling the components invalidateDisplayList(). Flex will then call this method on the next refresh interval.

Descriminate what can be dropped in ListBase Classes

2010 April 16
by admin

The project that I have been working on has required me to discriminate between what can and can’t be dragged between Lists and Trees. The default state for Lists is to accept any and all items that came from other Lists. The same goes for Trees. In my last post, I talked about overriding the List and Tree classes in order to allow Drag and Drop between them. This was done by modifying the accepted DragSource format. This post is an extension of the last post because we are actually going to discuss how to modify key value of the DragSource.

The best way to perform this operation is to change the hard coded key for the DragSource (“items” or “treeItems”) to a variable that can be instantiated publicly. I would recommend setting the dragSource key to a static constant that can be accessed globally. You will then want to override addDragData with the variable that you set instead of accepting the default (“items” or “treeItems”)

1
2
3
4
override protected function addDragData(ds:Object):void    // actually a DragSource
{
ds.addHandler(funcName, keyName);
}

Finally, to discriminate between allowable drop data you will want to override dragOverHandler and check if the data has the type you are looking for.

1
2
3
4
5
6
7
8
9
if (iteratorValid && (event.dragSource.hasFormat(acceptedDropType1) || event.dragSource.hasFormat(acceptedDropType2)))
{
DragManager.acceptDragDrop(this);
DragManager.showFeedback((event.ctrlKey || event.altKey) ?
DragManager.COPY :
DragManager.MOVE);
showDropFeedback(event);
return;
}

Dragging and dropping between Lists and Trees

2010 April 16
by admin

Although it may seem like Lists and Trees are completely different components, they actually extend from the same family which is ListBase. A Tree actually is actually a list at a lower level

1
2
public class Tree extends List implements IIMESupport
{

With that said, your probably wondering why drag and drop between Lists and Trees doesn’t work natively.  To explain let’s discuss the DragManager Class.  There are two methods in the DragManager Class that we will discuss including doDrag and acceptDragDrop.  Every Drag Operation within Flex is initiated by calling the doDrag including those in ListBase Classes.  The doDrag operation is called with the following required variables:

1
doDrag(dragInitiator:IUIComponent, dragSource:DragSource, mouseEvent:MouseEvent);

The DragSource Class contains the data (DisplayObject) that is being dragged.  You can also assign other data to the DragSource just as you would be able to add it to any other Display Object.  This can be done directly by using addData with a key and an object or indirectly by using addHandler with a key and a Function.  The DragSource variable is what differs between a List and a Tree and is why you can’t drag and drop between Trees and Lists by default.  All Items in a tree are added and accessed with a key value “treeItems” while items in a list are added and accessed with a key value of “items”.

Here is the function within the ListBase class where the DragSource data is set

1
2
3
4
protected function addDragData(ds:Object):void // actually a DragSource
{
ds.addHandler(copySelectedItems, "items");
}

And here is the function within the Tree Class where the DragSource data is set

1
2
3
4
override protected function addDragData(ds:Object):void    // actually a DragSource
{
ds.addHandler(collapseSelectedItems, "treeItems");
}

By default a List accepts drops of items that have the format “items” and a tree accepts items that are of type “treeItems”.  You can see this by looking at the code inside dragEnterHandler.

1
2
3
if (enabled && iteratorValid && event.dragSource.hasFormat("items"))
{
DragManager.acceptDragDrop(this);

Unfortunately “items” is hard coded instead of being set by a variable.  For this reason, Dragging and dropping between lists and Trees will require you to Extend List and Tree and override any drag and drop operation where “items” or “treeItems” is hard coded.  This includes dragEnterHander, dragOverHandler and dragDropHandler.  The if statement above could be changed to the following the make this work.

1
2
 if (enabled && iteratorValid && (event.dragSource.hasFormat("items") || event.dragSource.hasFormat("treeItems"))
{

Once you have created a custom List and Tree that follows the above conventions dragging and dropping between Lists and Trees will work as expected.