Showing posts with label ItemRenderer. Show all posts
Showing posts with label ItemRenderer. Show all posts

GroupingCollection example featuring GroupingFunction

english mobile

Several months ago, I built a dashboard example for a client that featured a calendar with a month view like you'd see in a paper calendar on one side and a week view on the other side. I wound up writing some fairly complex classes to handle the different breakdowns in how the data displayed. I also wrote a custom renderer for the calendar page and a different one for the week view.

And then I had to do some work with the AdvancedDataGrid and fell in love with the way this component "thinks" about data, with its HierarchicalData, HierarchicalCollectionView, and GroupingCollection. And, of course, I adore its styleFunction, as you might have guessed from my earlier TileList_withStyle and DataGrid_withStyle classes.

A few weeks ago, someone posted an example that showed a way to use GroupingCollections with controls that were not AdvancedDataGrid or Tree components. Let me tell you, that got my little cogs twirling. If only (thought I) you could use a function to decide how the items in a GroupingCollection grouped. Then you could use it to group dates into years, months, weeks, whatever floated your boat. So I went digging into the docs, and found that the GroupingField actually does have such a property.

And so the GroupingFunction example was born. This example illustrates how you can create a single array of objects that contain the dates to use for a Calendar application, then group and filter the data in different ways by using that array as the source for multiple ArrayCollections and GroupingCollections. These allow you to display that data in several different ways without a lot of manual parsing.





It also illustrates the following concepts:



  • Using a single itemRenderer with the TileList_withStyle component to present different appearances based on the styleFunction you use.

  • Using a Repeater to populate an Accordion control based on a data source

  • Using a single child component that gets reused between the children of
    the Accordion


I'd also like to point out that I'd have never been able to create this example if I weren't still looking for work. I'm sure you're probably loving being the recipient of all these free examples, but please return the favor by passing my name on to anyone you know who is hiring :-).



Updated October 21, 2008:

I changed the itemRenderer to show how you can set the blendMode on text to apply effects to it without embedding the font. I only set the blendMode on the lower label , so that the difference would be apparent.

Extended DataGrid with StyleFunction Example Posted

english mobile

A few weeks ago, I posted an example of an extended TileList that adds the styleFunction I've become so fond of with AdvancedDataGrid. I decided I'd look and see if I could do the same with DataGrid, and I found that, while it was challenging, I was able to do it. So I've posted my new extended DataGrid_withStyle and StyleableRenderer classes for you to use and enjoy. As always, View Source is enabled.

Debugging itemRenderers

english mobile

You may have notced that I have spent a lot of time chasing down issues with itemRenderers. It always frustrated me that you could get information on the parent of any component, but I could never figure out how to find out information on the renderers being displayed by a List based control.

I finally realized that if I set a break point in a scope that had a reference to a List control, I could rifle through the properties of that control until I found the rendererArray property, which seems to be an array of arrays. If you're not using a multi-column control, like a DataGrid or an AdvancedDataGrid, the itemRenderer for each row will be at the 0 index of each row index. Otherwise, each row will be the outer index of the rendererArray and each column will be an element in the row array.

I really do view this as my diary of Flex, and I got tired of not ever remembering what the name of the property is. It can take quite a while to fish through all the properties available on a control to try to relocate it. So I wrote it down, since it doesn't seem to be documented. Hope it helps you, too :-).

Musings on AdvancedDataGrid (Part 4)

english mobile

So, in part 3, I gave up on my extension of the AdvancedDataGridItemRenderer altogether and set my extended AdvancedDataGridGroupItemRenderer as both the itemRenderer and groupItemRenderer on the AdvancedDataGrid. This gave me a nice uniform appearance on all of my itemRenderers. So I set off happily to write my iconFunction.

This turned out to work exactly as advertised, with only one hitch--my leaf icons weren't rendering. Had I misunderstood? Did the iconFunction (as opposed to groupIconFunction) work only for grouping rows? Well, no, as it turns out.

If you'll recall, way back in Part 2 I had a problem getting my styles to show up in my first column, so I set the itemRenderer on that column to my extended AdvancedDataGridItemRenderer. Even after I did this, though, some cells still didn't show my styles. At the time, I didn't understand what that meant.

Lesson Number 3: All itemRenderers in the tree column will use the specified groupItemRenderer, unless you specifically tell that column to use something else. Even if you do tell that column to use something else, it will still use the groupItemRenderer for (ahem) grouped items.

Once I figured that out, it was obvious to me that by removing the itemRenderer property on that column, I would then have 100% of cells using my extended AdvancedDataGridGroupItemRenderer, which had the existing icon functionality plus my added functionality for setting the background based on a style passed in through the styleFunction.

Great! Wonderful! But I then found that my particular data structure depended on knowing something about both the parent node and the child node in order to know what to do with an item click, and I couldn't figure out how to get the information about a strongly typed parent from a strongly typed child that might be the child of more than one parent.

Tomorrow, I will write about how I got this information.

Musings on AdvancedDataGrid (Part 3)

english mobile

Review Part 2

The author of the blog post I originally found that inspired this journey said that this method would not cause the selection and rollover indicators to be obscured in the same way as this method. But I really wanted to be able to see these indicators, rather than a tiny edge around each row. So I was determined that I was going to get my AdvancedDatagridItemRenderer to allow me to see these indicators through it.

The first thing I'd tried, just setting the alpha property, hadn't worked. The next thing I tried was to try to use the graphics functions to draw a background like I did in the AdvancedDatagridGroupItemRenderer. Unfortunately, since the AdvancedDatagridItemRenderer does not inherit from UIComponent or DisplayObjectContainer, so it neither had a graphics object of its own nor any way to add one.

So I stuck my nose back into the docs and discovered that my TextField had a colorTransform object that I should be able to manipulate to change the alpha transparency. Well, I was able to change its alpha property, but there was absolutely no visible change.

Finally, I realized I was going to have to leave the Flex world and see what the Flash world had to offer. So I came across this post and was able to get the transparency by changing the blend mode. Still, my AdvancedDatagridItemRenderer and AdvancedDatagridGroupItemRenderer did not match, because the text in the AdvancedDatagridItemRenderer was semitransparent and the AdvancedDatagridGroupItemRenderer text was not. Lesson Number 2: Anything that inherits from TextField is only going to be able to support alpha transparency with difficulty, and even then the entire component, including the text, will be alpha transparent.

So I had the simple idea that I could use the AdvancedDatagridGroupItemRenderer to do all the item rendering.

Tomorrow, I will talk about getting the icons to render properly.

Musings on AdvancedDataGrid (Part 2)

english mobile

Review Part 1

I'd found a neat little sample that shows how to change the background color on the row by extending AdvancedDataGridItemRenderer (ADGIR) to set the existing background and backgroundColor properties based on a style set on the component.

I had no trouble copying this, but I found that for some reason the entire first column stubbornly refused to pick up my carefully applied color. Undaunted, I set the itemRenderer property of the first column explicitly to my extended ADGIR.

The result I had was closer to what I wanted--most of the cells in that column now had the color my styleFunction had insisted upon--but the ones with the triangle in them remained white. Aha! Clearly this was a different thing altogether, so I went back to the docs and looked for inspiration. It seems that the uncolored cells were being rendered by another component, the AdvancedDataGridGroupItemRenderer (ADGGIR).

So I set about extending that worthy component. At first, I thought I'd be able to just cut and paste the code I'd modified for my ADGIR, but no such luck. Unfortunately, the ADGGIR had no background or backgroundColor properties. So I fell back on more conventional tactics, drawing a rectangular background on the component when the style changed. First lesson: the AdvancedDataGridItemRenderer is based on the Flash TextField component and the AdvancedGridGroupItemRenderer is based on UIComponent. These two components have completely different capabilities and must be dealt with in entirely different ways.

As soon as I saw my extended ADGGIR next to the extended ADGIR, I realized that the ADGIR was not yeilding to my attempts to set its alpha transparency. I'd included code in both to set the alpha transparency, but it was only working in the ADGGIR.

Tomorrow, I'll talk about my attempts to add alpha transparency to the ADGIR.

Using a CSS TypeSelector with an itemRenderer

english mobile

Today, I had more fun with item renderers. I had a component I was working on to try to prototype some new functionality, and I had set up styles for it in the <mx:styles> declaration of the Application tag. If I put my component in a container in the main Application, the style came through fine. If I used it as an itemRenderer of a List based class, only the text styles worked.

It seems that when you use a component this way, Flex will assign ListBaseContentHolder as the style name instead of the class name, but for some reason this only negates things like backround colors—text declarations come through just fine. This interesting feature isn't documented anywhere, so it took me a whole day to figure out the fix, which is so simple I wanted to pound my head against the wall till I couldn't see straight.

override protected function commitProperties():void{
this.styleName = this.className;
}

Hope this saves someone some time!

Another good itemRenderer Resource

english mobile

The longer I use Flex, the more firmly I believe that the key to understanding it is the component life cycle. Specifically, the life cycle as it applies to item renderers. Today on Flex Coders, Douglas Knudsen posted a link to this great presentation on the component life cycle by Eli Greenspan. I can't for the life of me figure out how to bookmark to a pdf, but if I post a link here, I'll be able to find it forever :-).

Great ItemRenderer Resource

english mobile

I really struggle with itemRenderers--what goes where to make what you want to occur happen when you want it to. So I've been talking to various people and reading, reading, reading trying to make sense of it all. From the posts on the yahoo FlexCoders group, it seems like I'm not the only one experiencing confusion.

I think the biggest problem is that there don't seem to be many "from the ground up" resources on this subject. But that doesn't mean there aren't any. In addition to the Flex help and LiveDocs, which, let's face it, confuse us as much as inform us, there are several blogs that tackle this subject. Today I found Peter Ent's blog, which contains a five part series just on itemRenderers. Thanks, Peter!

Is the HorizontalList faster than an HBox with a Repeater?

english mobile

The Help files that come with Flex Builder claim that the HorizontalList control can have better performance than a HBox with a repeater:

"...performance of a HorizontalList control can be better than the combination of an HBox container and a Repeater object because the HorizontalList control only instantiates the objects that fit in its display area."

The truth is, this statement is false. The HorizontalList always instantiates one more control than is drawn in the display area. This extra component is created simply for measurement purposes and is kept in memory in case extra measurements need to be done. That's highly ironic, as I'll get to in a moment.

In a situation where the number of items does not exceed the area available, the HBox with a repeater component will instantiate exactly the number of renderers as items in your dataprovider, whereas the HorizontalList will instantiate one more. If your itemRenderers are heavy (for instance, if they themselves have a component that takes an itemRenderer), this difference can be significant. Additionally, Repeaters do offer the ability to recycle their renderers, which offsets most of the performance advantage you might get from a HorizontalList.

The second problem with the way the HorizontalList "does business" is more significant. If you have to use callLater to do anything that affects the size of the itemRenderers, the HorizontalList has already measured the component before the call that changes the size, and so the space it allocates to the renderer will not be the actual size of the renderer. And there doesn't appear to be any way to dispatch any events from the renderer or set any variables or call any methods that will convince the HorizontalList to use that extra, useless itemRenderer that is hanging around at the new and improved size to update the size.

Possibly you could subclass HorizontalList to make this work correctly, but why would you, since the HBox with an ItemRenderer just works?

Updated May 19: Today, I discovered that the HorizontalList doesn't always draw this extra renderer. If you specify a rowHeight, this step will be skipped.

Updated September 11, 2008: I think if I'd overridden measure() in my itemRenderer to explicitly report the size after the dataProvider was set in commitProperties, I could have gotten a HorizontalList to work. I later had a similar problem with a regular List, and overriding measure() fixed it.

Showing item number in ItemRenderer

english mobile

I asked a question several weeks ago on the FlexCoders forum on how to get the item number of an item that had been clicked in a Repeater. None of the answers that I got seemed to help and it wasn't that critical, so I let it drop. In my current project, it is critical, because I have to show that number on the screen.

Luckily, I am using XML. E4X XML, like Authorware icons, is very "self-aware." In Authorware, you can get from any place in the program to any other place using the numeric values implicit in the parent/child relationship. Similarly, an E4X XML node "knows" what its child number is relative to the parent node. So displaying the node number on the screen was as simple as {data.childIndex + 1}.

Some days Flex is really cool :-).

Updated 12-3-08:
I've posted a simple example that shows how to display the line number in a List based control with either an XML or ListCollectionView source.

Order of Events for ItemRenderers

english mobile

I suspect that I'll be blogging a lot about ItemRenderers, because it seems that there's a ton that can go wrong with them and lots of stuff to learn before you can get it right. A good starting point in learning about them is Alex Harui's Blog. I found this source a bit misleading in my current project, because it suggests that you should run your init code in the dataChange event listener function.

The problem I found is that the dataChange event runs before some objects in the component have been instantiated, so trying to change their attributes results in a spectacular explosion. The solution I found is to set a boolean value in the creationComplete listener to indicate whether or not the component was completely drawn, then run the same logic that would have run from the dataChange function. So when the data changes, the dataChange listener will initialize the objects, but on first creation, the creationComplete listener handles it.

I suspect this is not the optimal way to handle this, but it works and doesn't require much rocket science on my part.

Update 7/3/2008: I eventually had a series of conversations about this with Alex, and it seems that the mistake I was making was that I was trying to address objects directly in the dataChange event handler, and, as noted above that doesn't work. But instead of repeating that call in dataChange and creationComplete, what I should have done is to set a boolean flag in dataChange only to indicate that the property (which in this case was a dataProvider) needs to be set on the child object.

I was trying to avoid overriding any of the inbuilt methods, but the engineers intended for developers to override many of the methods when creating itemRenderers. In this case, I needed to override commitProperties and set the dataProvider whenever that flag was true (and then set the flag back to false, of course).