<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Peter Ent</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/" />
<modified>2008-07-15T14:00:13Z</modified>
<tagline>Tips to give your RIA more FLEXappeal!</tagline>
<id>tag:weblogs.macromedia.com,2008:/pent//32</id>
<generator url="http://www.movabletype.org/" version="3.16">Movable Type</generator>
<copyright>Copyright (c) 2008, pent</copyright>
<entry>
<title>(re)Genesis</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/07/regenesis.html" />
<modified>2008-07-15T14:00:13Z</modified>
<issued>2008-07-10T13:23:55Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.15009</id>
<created>2008-07-10T13:23:55Z</created>
<summary type="text/plain"> I started a whole new career path in November 2004 when I joined the Flex Support team at Macromedia. In the 3+ years since, I have answered a lot (and I mean, a lot) of questions from Adobe customers....</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[  <p>I started a whole new career path in November 2004 when I joined the Flex Support team at Macromedia. In the 3+ years since, I have answered a lot (and I mean, <em>a lot</em>) of questions from Adobe customers. Starting on Monday, July 14 2008, I will be joining a new team on something we call <font color="#FF6600">Genesis</font>.</p>
  <blockquote>
    <p>Visit the Genesis Blog at <a href="http://blogs.adobe.com/mashup">http://blogs.adobe.com/mashup</a>.</p>
    <p>You can read more about Genesis in this article at IT World: <a href="http://www.itworld.com/news/53488/adobe-readying-new-mashup-tool-business-users">Adobe readying new mashup tool for business users</a>.</p>
  </blockquote>
  <p>I have enjoyed working for the best managers (Eric Anderson, Jim Schley, and Judy Ricciarelli) and with the best teammates (Woojin Choi, Kurt Mossman, Lin Lin, Brandon Purcell, Kyle Quevillon, Patrick Simon, Nick Watson, Peter Watson, John Zhao). Customer support is a team effort and I think the Flex Support team has proven that with the best-in-the business product support. </p>
  <p>My new adventure with the Genesis group turns me back into a developer working on an exciting product sure to find a home in any coporation. Everyone needs a change of pace now and again and I'm delighted to be able to stay with Adobe and work with the best people in the business. I just hope I'm up for the challenge.</p>
  <p>I'm still going to keep blogging and making Flex and AIR more accessible. Stay tuned for more articles. <br/>
        </p>
]]>

</content>
</entry>
<entry>
<title>Adobe Reader 9 is Here!</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/07/adobe_reader_9.html" />
<modified>2008-07-02T14:52:25Z</modified>
<issued>2008-07-02T14:51:23Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14998</id>
<created>2008-07-02T14:51:23Z</created>
<summary type="text/plain">Adobe Reader 9 adds new capabilities, better performance and stronger security. Here are the highlights: Improved launch speeds Looking for faster launch speeds? Adobe has enhanced general performance and, in particular, has reduced launch times with Adobe Reader 9. Try...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>General Interest</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<p>Adobe Reader 9 adds new capabilities, better performance and stronger security. Here are the highlights:</p>

<p><strong>Improved launch speeds</strong><br />
Looking for faster launch speeds? Adobe has enhanced general performance and, in particular, has reduced launch times with Adobe Reader 9. Try it: You'll notice the difference.</p>

<p><strong>PDF Portfolios</strong><br />
Packages, introduced in Adobe Reader 8, have been greatly enhanced and renamed. Portfolios provide easy navigation when you work with multiple PDF documents and other document types. They also enable you to work with a collection of materials such as drawings, e-mail messages, spreadsheets, and videos as a single file, which makes distribution, storage, retrieval, and collaboration easy for end users.</p>

<p><strong>Native Adobe Flash support</strong><br />
Adobe Reader 9 can natively display rich media content, which you'll notice immediately with Portfolios. Interested in viewing SWF and FLV files? Adobe Reader 9 is the answer.</p>

<p><strong>Acrobat.com (beta)</strong><br />
In addition, Adobe Reader 9 includes easy access to Acrobat.com (beta), an exciting new set of online services from Adobe. With Acrobat.com, you can create PDF files online; create and coauthor documents with others; host live web meetings; upload and share PDF files and other types of documents and control who has access to them; and even embed a rich, interactive preview of your document in a web page. All of these services and more are provided online, so you can access them from anywhere. And you'll find easy access points from within Reader 9. As an added convenience, Acrobat.com leverages Adobe AIR, so you can interact with Acrobat.com from your desktop. Acrobat.com on Adobe AIR is a small application that is included with your download of Adobe Reader 9. Available in select languages.</p>

<p><strong>Security enhancements</strong><br />
Adobe Reader 9 provides new digital signature functionality for an improved user experience. The new version also adds support for 256-bit AES encryption and new advanced security capabilities.</p>

<p>But, that's not all. Adobe Reader 9 offers a new PDF Standards Pane, improved CAD and geospatial functionality and accessibility enhancements. </p>

<p>So, <a href="http://www.adobe.com/products/acrobat/readstep2.html">download Adobe Reader 9</a> now! Or, <a href="http://www.adobe.com/products/acrobat/distribute.html">distribute Adobe Reader 9</a> in your enterprise or bundle it with a CD or computer!<br />
</p>]]>

</content>
</entry>
<entry>
<title>MAX North America Site is Up</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/06/max_north_ameri.html" />
<modified>2008-06-25T15:23:38Z</modified>
<issued>2008-06-25T15:21:35Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14989</id>
<created>2008-06-25T15:21:35Z</created>
<summary type="text/plain">Please visit the MAX NA Experience site: http://max.adobe.com/na/experience/ It is a 100% Flash based website with interactive landscapes (click the background). The backgrounds were created by several of the best digital design agencies on the planet. If you can figure...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<p>Please visit the MAX NA Experience site:</p>

<p><a href="http://max.adobe.com/na/experience/">http://max.adobe.com/na/experience/</a></p>

<p>It is a 100% Flash based website with interactive landscapes (click the background). The backgrounds were created by several of the best digital design agencies on the planet. If you can figure out the puzzles, you discover who built them.</p>

<p>After the site launches, click on the background. When it appears, click again. There are three backgrounds - the one in the middle, one to the right, and a very cool tropical one to the left.</p>]]>

</content>
</entry>
<entry>
<title>itemEditors - Part 3</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/06/itemeditors_-_p_2.html" />
<modified>2008-06-17T17:30:15Z</modified>
<issued>2008-06-17T17:22:42Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14982</id>
<created>2008-06-17T17:22:42Z</created>
<summary type="text/plain">itemEditor,itemRenderer The previous article in this series discussed item editing events. Using events can make your application respond to what the user enters and help the user make fewer mistakes. This article is about using itemRenderers as itemEditors - one...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Components</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<!-- #BeginTags --><p class="tags"><a href="http://www.technorati.com/tag/itemEditor" rel="tag">itemEditor</a>,<a href="http://www.technorati.com/tag/itemRenderer" rel="tag">itemRenderer</a></p><!-- #EndTags -->
  <p>The previous article in this series discussed item editing events. Using events can make your application respond to what the user enters and help the user make fewer mistakes.</p>
  <p>This article is about using itemRenderers as itemEditors - one class to do both display data and edit the data. I tend to think of it more as an itemEditor used as an itemRenderer. But that's just me.</p>
<blockquote>
<a href="http://weblogs.macromedia.com/pent/archives/part3.zip">Download source for these examples.</a>
</blockquote>
  <p>Further, I have to be honest and say I am not a big fan of the renderer-as-editor; I think renderers should present data and editors should edit it. There are a few occasions when I think it is a good idea to use a single class for both, but those times are very few in my opinion. </p>
  <h3>Examples</h3>
  <p>Here is an example of over-using the itemRendererAsEditor. The DataGrid on the left is a nice, clean DataGrid. All of the cells are editable and when you click or tab into a cell its editor appears. The DataGrid on the right uses itemEditors to render the cells and edit them. All you see are the editors: TextInput controls for some columns, a ComboBox for another, and a NumericStepper for the last. Lots going on, very busy to look at.</p>
  <table width="222" cellspacing="6" border="0">
    <tr valign="top">
      <td width="100"><img src="http://weblogs.macromedia.com/pent/fig1.gif" width="300" height="116" /></td>
      <td width="100"><img src="http://weblogs.macromedia.com/pent/fig2.gif" width="300" height="136" /></td>
    </tr>
    <tr valign="top">
      <td>itemEditors only </td>
      <td>itemRenderers as itemEditors </td>
    </tr>
  </table>
  <p>Here is an example of using the CheckBox as both an itemRenderer and an itemEditor. I think the CheckBox works really well for this. It is clean, simple control and you can readily see whether a value is true or false. Plus you can just click it to change it. Straightforward implementation, good user experience.</p>
  <p><img src="http://weblogs.macromedia.com/pent/fig3.gif" width="300" height="116" /></p>
  <p>Here is another example of using an itemEditor as a renderer. This List control represents a shopping cart. In it are all of the things you have added to your cart while shopping online at your favorite grocery store. </p>
  <p><img src="http://weblogs.macromedia.com/pent/fig4.gif" width="300" height="179" /></p>
  <p>As you can see, the quantity of each item in the cart is represented by a NumericStepper. All the user has to do is change the quantity and the cart is updated. A delete button would also be a good idea here, too.</p>
  <h3>Shopping Cart </h3>
  <p>This complex editor/renderer class works as follows:</p>
  <pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" verticalAlign="middle" paddingRight="4" paddingLeft="4" &gt;

    &lt;mx:Script&gt;
    &lt;![CDATA[
        <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> get quantity() : Number
        {
            <font color='#f46d0a'>return</font> itemQuantity.value;
        }
    ]]&gt;
    &lt;/mx:Script&gt;
    
    &lt;mx:CurrencyFormatter id="cfmt" precision="2" /&gt;
    
    &lt;mx:Label text="{data.name}" fontWeight="bold" fontSize="12"/&gt;
    &lt;mx:Spacer width="100%"/&gt;
    &lt;mx:NumericStepper id="itemQuantity" value="{data.quantity}" 
        minimum="0"
        maximum="100"/&gt;
    &lt;mx:Label text="{cfmt.format(data.price*itemQuantity.value)}" width="66"/&gt;
    
&lt;/mx:HBox&gt;</pre>
<p>As with every itemEditor, this one has a property used as the <font color="#FF6600">editorDataField</font>. In this case it is the <font color="#FF6600">quantity</font> property getter function. The function retrieves the value setting of the NumericStepper (with id itemQuantity). </p>
<p>As an itemRenderer, this component must also display the current quantity (as well as the product name, price, and sub-total). These values are displayed through data binding. The sub-total is actually an ActionScript expression, multiplying the price by the value of the NumericStepper. As the NumericStepper is changed so does the sub-total. </p>
<p>Now you are probably wondering how to get the grand total below the shopping cart to update as the NumericSteppers are changed. Simply changing the sub-total and the quantity field of the itemRenderer/Editor will not update the grand total. Remember that the editor does not commit the new value into the data provider until after the edit completes. In other words, if you increase the value of the NumericStepper for the Snow Peas row, the grand total will not update until focus leaves the Snow Peas row. This is so you can validate the information as shown in previous articles.</p>
<p>For a shopping cart like this, you want the grand total to update as the user changes the NumericSteppers. So you have to force the situation a little.</p>
<p>The first thing you  do is have the itemRenderer class implment the IDropInListItemRenderer interface. This gives you access to the listData which contains a reference to the list itself and, through that, to the dataProvider.</p>
<blockquote>
  <p>The code demonstrating this is available in the download. Look for the ShoppingCartRendererExtra.mxml file. </p>
</blockquote>
<p>Once you have the   listData you can have the change event on the NumericStepper force an update on the dataProvider:</p>
<pre>private <font color='#f46d0a'>function</font> forceUpdate() : void
{
    <font color='#6eb4d4'>// Access the collection - listData.owner is the List and from there you have its dataProvider.</font>
    <font color='#f46d0a'>var</font> ac:ArrayCollection = (listData.owner as List).dataProvider as ArrayCollection;
    
    <font color='#6eb4d4'>// update the quantity field from the numeric stepper. This is what the List will automatically</font>
    <font color='#6eb4d4'>// do when editing completes, but since you want to see the grand total change as the NumericStepper</font>
    <font color='#6eb4d4'>// changes, you have to force things a bit.</font>
    data.quantity = itemQuantity.value;
    
    <font color='#6eb4d4'>// finally, tell the collection the data changed. this will cause the collection to</font>
    <font color='#6eb4d4'>// dispatch its own change event which is then picked up by the main application.</font>
    ac.itemUpdated(data);
}</pre>
<p>When the NumericStepper's change event triggers this event handler, the ArrayCollection has the item updated immediately, rather than waiting for the List to complete editing the cell. If the main application is listening for a COLLECTION_CHANGE event on the collection, the grand total can be calculated:</p>
<pre>    &lt;mx:ArrayCollection id="shoppingCartDB" 
        source="{shoppingCartArray}"
        collectionChange="updateCartTotal()" /&gt;
...
<font color='#f46d0a'>private</font> <font color='#f46d0a'>function</font> updateCartTotal() : void
{
    <font color='#f46d0a'>if</font>( cartTotal ) {
        <font color='#f46d0a'>var</font> total:Number = 0;
        <font color='#f46d0a'>for</font>(<font color='#f46d0a'>var</font> i:int=0; i &lt; shoppingCartDB.length; i++)
        {
            <font color='#f46d0a'>var</font> record:Object = shoppingCartDB.getItemAt(i);
            total += record.price * record.quantity;
        }
        
        cartTotal.text = cfmt.format(total);
    }
}</pre>
<h3>&#160;</h3>
<h3>Conclusion</h3>
<p>Take care when turning an itemRenderer into an itemEditor. The user should have a straightforward interface with a single purpose when editing a cell or record. I personally prefer to separate the functions, but there are times when using  an itemRenderer as an itemEditor  can make sense, even if you have to go the extra mile as with this shopping cart grand total example. </p>
<p>         <br/>
    </p>
]]>

</content>
</entry>
<entry>
<title>itemEditors - Part Two</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/06/itemeditors_-_p_1.html" />
<modified>2008-06-04T18:15:20Z</modified>
<issued>2008-06-04T18:15:16Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14961</id>
<created>2008-06-04T18:15:16Z</created>
<summary type="text/plain"> Editing Events and Complex Editors In the last article of this series you saw how to make some simple inline itemEditors. If you have read the series on itemRenderers, then you noticed how similar the two are. The key...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Components</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[
  <h3>Editing Events and Complex Editors</h3>
  <p>In the last article of this series you saw how to make some simple inline itemEditors. If you have read the series on itemRenderers, then you noticed how similar the two are.</p>
  <p>The key to making an itemEditor work is a) naming the class using the <font color="#FF6600">itemEditor</font> property and b) naming the value property of the itemEditor using the <font color="#FF6600">editorDataField</font> property. </p>
  <p>In this article I'll show you how to use events to do some simple data validation and to prevent certain cells from being edited. In the course of this you will see how to make more complex itemEditors.</p>
  <blockquote>
    <p><a href="http://weblogs.macromedia.com/pent/part2.zip">You can download the source code for this example here</a>. </p>
  </blockquote>
  <p>A word of caution here: by &quot;complex&quot; I do not mean editors with many controls and layouts. I really mean slightly more complex than inline itemEditors. The reason being is that I think it is unfair to ask users to make complex edits within a list or cell of a DataGrid. An editor should be focused only one one thing: the contents of a cell. For example, if you are using the List control and presenting a shopping cart, it is not unreasonable to allow the user to change the quantity of the items in the cart by letting them edit that value right in the cell. What would be unreasonable is to allow them to change the item itself, the colors, quantity, special instructions, and so forth. Or in other words, allow them to shop for items right from the cart when you have a whole site that does that. The cart is just a checkout convenience. Sure, let them add an extra tub of ice cream or delete a bag of chips, but don't have them turn the bag of chips into a two boxes of whole wheat pasta.</p>
  <h3>The itemEditEnd event</h3>
  <p>Let's say you have a DataGrid which helps you mange inventory. One of things you can do is change part numbers, but you cannot allow a part number to be blank. Using the default itemEditor, the TextInput control, you can click on a cell in the &quot;Part #&quot; column, press the delete key and erase the part number. This is one technique to prevent that.</p>
  <pre>	&lt;mx:DataGrid x="10" y="64" editable="<font color='#f46d0a'>true</font>" dataProvider="{inventoryDB}" 
		<b>itemEditEnd="verifyInput(event)"&gt;</b>
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn headerText="Product" dataField="product"/&gt;
			&lt;mx:DataGridColumn headerText="Part #" dataField="part"/&gt;
			&lt;mx:DataGridColumn headerText="Type" dataField="type"
				itemEditor="editors.ProductTypeEditor" editorDataField="type"/&gt;
			&lt;mx:DataGridColumn headerText="Quantity" dataField="quantity"/&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;</pre>
<p>The list controls dispatch an <font color="#FF6600">itemEditEnd</font> event whenever editing is <em>about</em> to be completed. The event happens before the data is  commited back to the dataProvider. By handling this event you have the option of changing the data, validating the data, and stopping the commit if necessary. For this example, the verifyInput() function will make sure the product part number is not empty.</p>
<pre>		<font color='#f46d0a'>private</font> <font color='#f46d0a'>function</font> verifyInput( event:DataGridEvent ) : void
		{
			<font color='#00dd00'>// it is OK if the user cancels the edit</font>
			<font color='#f46d0a'>if</font>( event.reason == DataGridEventReason.CANCELLED ) <font color='#f46d0a'>return</font>;
			
			<font color='#00dd00'>// grab the instance of the itemEditor. For this DataGrid, only the
			// TextInput control is used as the editor, so it is safe to get the
			// editor no matter what column has been edited.</font>
			<font color='#f46d0a'>var</font> editor:TextInput = (event.currentTarget as DataGrid).itemEditorInstance as TextInput;
			
			<font color='#00dd00'>// if  the edit is on the part number column, make sure it is not blank</font>
			<font color='#f46d0a'>if</font>( event.dataField == "part" )
			{
				<font color='#f46d0a'>if</font>( editor.text.length == 0 ) {
					<font color='#00dd00'>// call event.preventDefault() so the edit will not continue and store the</font>
					<font color='#00dd00'>// blank value</font>
					event.preventDefault();
					<font color='#00dd00'>// give the editor an error to display to the user</font>
					editor.errorString = "You must enter a part number";
					<font color='#f46d0a'>return</font>;
				}
			}
			
			<font color='#00dd00'>// handle other columns here</font>
		}</pre>
<p>The event is a DataGridEvent and contains some very useful properties. The <font color="#FF6600">reason</font> property tells you why the event was dispatched. If the user pressed the ESCAPE key or clicked outside of the DataGrid the reason will be DataGridEventReason.CANCELLED. You may want to ignore this event as I have done and just let the DataGrid to its default action which is to cancel the edit and restore the previous value. </p>
<p>If you have decided to handle the event then you will need the itemEditor to get to its properties. The event's <font color="#FF6600">currentTarget</font> property contains the control which I have cast to DataGrid. The DataGrid has an <font color="#FF6600">itemEditorInstance</font> property which I cast to TextInput which is the type of itemEditor for this example. </p>
<p>This event handler is called for any cell so you must determine if the edit is something you are interested in pursuing. I check the event's <font color="#FF6600">dataField</font> property to make sure it is the &quot;part&quot; column. If so, I test the editor's text property to see if there are any characters in it. If there are no characters, two things happen:</p>
<p>First: the <font color="#FF6600">event.preventDefault()</font> is called. This is how to prevent the edit from happening - prevent the DataGrid from storing the new value back into the dataProvider.&#160; For the user, they will have pressed TAB or ENTER and nothing will appear to happen. The preventDefault() function will keep the itemEditor in place. </p>
<p>Second: I put an errorString onto the TextInput control. This is optional, but it does signal the user that there is something wrong. Afterall, they pressed the TAB or ENTER key and nothing happened. </p>
<h3>The itemEditBeginning Event</h3>
<p>There are times you might want to prevent a cell from being edited. You could set the DataGridColumn's editable property to false, but that prevents every cell from being edited. Suppose you just want to make <em>some</em> of the cells in the column uneditable? You can determine whether a cell is editable or not using the <font color="#FF6600">itemEditBeginning</font> event.</p>
<pre>    &lt;mx:DataGrid x="10" y="64" editable="<font color='#f46d0a'>true</font>" dataProvider="{inventoryDB}" 
        itemEditEnd="verifyInput(event)" 
        <b>itemEditBeginning="allowForEdit(event)</b>"&gt;
        &lt;mx:columns&gt;
            &lt;mx:DataGridColumn headerText="Product" dataField="product"/&gt;
            &lt;mx:DataGridColumn headerText="Part #" dataField="part"/&gt;
            &lt;mx:DataGridColumn headerText="Type" dataField="type"
                itemEditor="editors.ProductTypeEditor" editorDataField="type"/&gt;
            &lt;mx:DataGridColumn headerText="Quantity" dataField="quantity"/&gt;
        &lt;/mx:columns&gt;
    &lt;/mx:DataGrid&gt;</pre>
<p>Handling the itemEditBeginning event gives you the option of dynamically deciding the editability of a cell. In this example, the data has a field called <font color="#FF6600">permanent</font> on each record. The idea is that permanent=true means the product name is an unchangable value so the product cell for that row cannot be edited. This is handled by the allowForEdit() function:</p>
<pre>        <font color='#f46d0a'>private</font> <font color='#f46d0a'>function</font> allowForEdit(event:DataGridEvent) : void
        {
            <font color='#00dd00'>// if the field to be edited is a product, prevent the user from making</font>
            <font color='#00dd00'>// changes if the permanent flag is true<. You can use more complex logic, </font>
            <font color='#00dd00'>// of course.</font>
            <font color='#f46d0a'>if</font>( event.dataField == "product" ) {
                
                <font color='#f46d0a'>var</font> item:Object = ((event.currentTarget as DataGrid).dataProvider as ArrayCollection)[event.rowIndex];
                <font color='#f46d0a'>if</font>( item.permanent ) {
                    event.preventDefault();
                }
            }
            
            // handle other columns here
        }</pre>
<p>Again, the event is a DataGridEvent and here I have checked the dataField property of the event to make sure it is the &quot;product&quot; field I am dealing with. I can then get the record from the dataProvider of the DataGrid using the currentTarget property of the event and cast that to DataGrid. I then cast the DataGrid's dataProvider to ArrayCollection and get the event.rowIndex value. I could also have used the inventoryDB ArrayCollection directly in this function since they are in the same file, but this is more generic.</p>
<p>Once I have the record I can query its permanent property and if it is true, call the event.preventDefault() function to disable editing of that cell. In the case, the default behavior of itemEditBeginning is to present the itemEditor; preventing the default behavior makes the cell uneditable. </p>
<h3>Editing Limitations </h3>
<p>While I was proof reading this article   I thought of something you might try and do and offer a warning. When you are using these edit events and trying to determine if the event should proceed, you may be tempted to make a call to a backend or server process. For example, you may have a web service where you can validate a part number. You may be tempted, while inside of the <font color="#FF6600">itemEditEnd</font> event, to make a web service call and validate what the user just entered. Seems logical, right?</p>
<p>Logical maybe, but it won't work.  The reason is that data service calls are asynchronous. You can make the call, sure, but the result will be returned sometime later - well after your event handler has exited. In fact, your call won't actually be made until your function exits. Your call is queued and when the Flex framework exits the function the request will be made and then the result will be returned by your web service's result handler.</p>
<p>So there is no way to do this type of server-side validation while editing cells. You should query the server, when your application starts, for the data to validate against, then use that while the cells are being edited. </p>
<h3>Conclusion</h3>
<p> The ability to dynamically allow editing and to validate the edit is a excellent way to give your users a better experience. You can help them make fewer mistakes and give feedback during the editing process. You can prevent them from editing certain data and make it easier for yourself to write the application since you do not have to validate what the user cannot change. </p>
<p>In next article I'll cover itemRenderers used as itemEditors. <br/>
</p>
]]>

</content>
</entry>
<entry>
<title>itemEditors - Part 1</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/05/itemeditors_-_p.html" />
<modified>2008-05-29T22:39:16Z</modified>
<issued>2008-05-29T22:39:13Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14943</id>
<created>2008-05-29T22:39:13Z</created>
<summary type="text/plain"> inline itemEditors I recently completed a series on itemRenderers - customizations to list controls which format the display of the list contents. Displaying and rendering content is very cool and with Flex you can do nearly anything you can...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Components</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[
  <h3>inline itemEditors</h3>
  <p>I recently completed a series on itemRenderers - customizations to list controls which format the display of the list contents.  Displaying and rendering content is very cool and with Flex you can do nearly anything you can imagine. </p>
  <p>This new series covers itemEditors - a way to allow data to be changed directly inside of a list control. This first article covers inline itemEditors which are very simple, though quite useful, components you write directly inside your MXML files. The other articles in the series will cover more complex editing, validation, events, and using itemRenderers as itemEditors.</p>
  <p>The source code to this article is available by <a href="http://weblogs.macromedia.com/pent/InlineItemEditorSampleApp.mxml">downloading it here</a>. </p>
  <h3>TextInput Editor  </h3>
  <p>It is nice to edit directly in the list controls. You can imagine a DataGrid of warehouse inventory where you can adjust the content right in the grid without needing a special pop-up. The list controls have a built in editor - a TextInput control - which appears whenever the user clicks the mouse in an editable area, either a row (for a List), a branch (for a Tree), or a cell (for a DataGrid). All you need to do is set the list control's <font color="#FF6600">editable</font> property to true. For a DataGrid you can exclude a column from being edited by setting the DataGridColumn's <font color="#FF6600">editable</font> property to false.</p>
  <table width="234" cellspacing="10" border="0">
    <tr valign="top">
      <td width="100"><img src="http://weblogs.macromedia.com/pent/article1_figure1.jpg" width="300" height="123" /></td>
      <td width="100"><img src="http://weblogs.macromedia.com/pent/article1_figure1_001.jpg" width="300" height="116" /></td>
    </tr>
    <tr valign="top">
      <td><div align="center">Before editing a cell </div></td>
      <td><div align="center">After clicking on a cell, the editor opens and the content is ready for editing. </div></td>
    </tr>
  </table>
  <p>itemEditors differ from itemRenderers in that only one instance of the itemEditor is seen - just on the cell being edited. The itemEditor is not seen until the cell to be edited receives input focus. Then the itemRenderer is hidden and the itemEditor is moved to that position, sized to fit the area, and given the data for the record. When editing is finished (by moving focus to another location), the list control copies the new value from the editor to the dataProvider record.</p>
  <p>Using the image above as an example, when the user clicks in a cell of the &quot;Part #&quot; column, the dataProvider[row][dataField] value is given to the text property of the itemEditor (TextInput) control. When editing is finished, the text property value from the itemEditor (TextInput) control is copied to the dataProvider[row][dataField]. The dataProvider, being a collection, dispatches an event in response to the update.</p>
  <p>While the default TextInput control makes a fine editor, it really only works for the most simple of cases. It works fine for String values, for example, such as a book title, author name, or product number. If you need more control or want to validate the user's input, then you need to take matter into your own hands.  </p>
  <h3>Flex Controls as itemEditors </h3>
  <p>Here is how you make an itemEditor which only accepts numeric values:</p>
  <pre>	&lt;mx:DataGrid x="46" y="270" editable="<font color='#f46d0a'>true</font>" dataProvider="{employeeDB}"&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn headerText="Name" dataField="name"/&gt;
			&lt;mx:DataGridColumn headerText="Position" dataField="position"/&gt;
			&lt;mx:DataGridColumn headerText="Age" dataField="age"&gt;
			<b>	&lt;mx:itemEditor&gt;
					&lt;mx:Component&gt;
						&lt;mx:TextInput restrict="0-9" maxChars="3" /&gt;
					&lt;/mx:Component&gt;
				&lt;/mx:itemEditor&gt; </b>
			&lt;/mx:DataGridColumn&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;</pre>
<p>A very common control to use for an itemEditor is the CheckBox. This is very useful for editing Boolean values. Here is an example of using the CheckBox to edit the values for an &quot;In Stock&quot; column of an inventory program:</p>
<p><img src="http://weblogs.macromedia.com/pent/article1_figure3_001.jpg" width="300" height="122" /></p>
<pre>&lt;mx:DataGrid x="531" y="273" editable="<font color='#f46d0a'>true</font>" dataProvider="{inventoryDB}"&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn headerText="Product" dataField="product"/&gt;
			&lt;mx:DataGridColumn headerText="Part #" dataField="part"/&gt;
		<b>	&lt;mx:DataGridColumn headerText="In Stock?" dataField="inStock"
				labelFunction="inStockLabeler"
				itemEditor="mx.controls.CheckBox" editorDataField="selected" /&gt; </b>
			&lt;mx:DataGridColumn headerText="Quantity" dataField="quantity"/&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;</pre>
<p>In this example the content of the cells in this column are rendered using a labelFunction (inStockLabeler) which could display anything such as &quot;Yes&quot;, &quot;No&quot;, &quot;In Stock&quot;, or &quot;Out of Stock&quot;. The <font color="#FF6600">itemEditor</font> property is set to the mx.controls.CheckBox class. And there is another, equally important, property set on the DataGridColumn: <font color="#FF6600">editorDataField</font>. This field indicates the property of the itemEditor class to use to fetch the value when editing is finished. In this case it is the CheckBox's <font color="#FF6600">selected</font> property. When editing is finished, the DataGrid will use the CheckBox's selected property to replace the inStock property in the data record.</p>
<blockquote>
    <p>You may wonder why the example with the TextInput did not supply the editorDataField property. That is because the default value for editorDataField is &quot;text&quot; which just happens to be name of the property on the TextInput control holding the value.</p>
  </blockquote>
  <p>You can use this same technique with a number of Flex controls. Here is one for an order quantity column using NumericStepper:</p>
  <p><img src="http://weblogs.macromedia.com/pent/article1_figure4_000.jpg" width="300" height="116" /></p>
  <pre>	&lt;mx:DataGrid x="531" y="82" editable="<font color='#f46d0a'>true</font>" dataProvider="{inventoryDB}"&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn headerText="Product" dataField="product"/&gt;
			&lt;mx:DataGridColumn headerText="Part #" dataField="part"/&gt;
			&lt;mx:DataGridColumn headerText="In Stock?" dataField="inStock"/&gt;
		<b>	&lt;mx:DataGridColumn headerText="Quantity" dataField="quantity"
				itemEditor="mx.controls.NumericStepper" editorDataField="value"/&gt; </b>
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;</pre>
<p>Notice the editorDataField is &quot;<font color="#FF6600">value</font>&quot; - the property of the NumericStepper which holds the current value of the control. Make sure you use the fully-qualified class name for the itemEditor property. </p>
  <h3>Complex Editor </h3>
  <p>Now suppose you want to do something a little more complex that doesn't have a ready-made Flex control available. Here is one which allows a credit card number to be entered using 4 separate 4-digit fields:</p>
  <p><img src="http://weblogs.macromedia.com/pent/article1_figure5.jpg" width="300" height="154" /></p>
  <pre>	&lt;mx:DataGrid x="46" y="463" editable="<font color='#f46d0a'>true</font>" dataProvider="{accountDB}" width="302"&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn headerText="Account" dataField="account" width="100"/&gt;
			&lt;mx:DataGridColumn headerText="Credit Card" dataField="ccard" editorDataField="value"&gt;
				<b>&lt;mx:itemEditor&gt;
					&lt;mx:Component&gt;
						&lt;mx:HBox&gt;
							&lt;mx:Script&gt;
							&lt;![CDATA[
								<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> get value() : String
								{
									<font color='#f46d0a'>return</font> part1.text+part2.text+part3.text+part4.text;
								}
								<font color='#f46d0a'>override</font> <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data(value:Object):void
								{
									super.data = value;
									part1.text = value.ccard.substr(0,4);
									part2.text = value.ccard.substr(4,4);
									part3.text = value.ccard.substr(8,4);
									part4.text = value.ccard.substr(12,4);
								}
							]]&gt;
							&lt;/mx:Script&gt;
							&lt;mx:TextInput id="part1" maxChars="4" restrict="[0-9]" width="40" /&gt;
							&lt;mx:TextInput id="part2" maxChars="4" restrict="[0-9]" width="40" /&gt;
							&lt;mx:TextInput id="part3" maxChars="4" restrict="[0-9]" width="40" /&gt;
							&lt;mx:TextInput id="part4" maxChars="4" restrict="[0-9]" width="40" /&gt;
						&lt;/mx:HBox&gt;
					&lt;/mx:Component&gt;
				&lt;/mx:itemEditor&gt;</b>
			&lt;/mx:DataGridColumn&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;</pre>
<p>This inline itemEditor follows the same rules as other itemEditors and names the editorDataField as &quot;value&quot;.  The component chosen for the itemEditor is the HBox - <strong>which does not have a &quot;value&quot; property</strong>. To make this itemEditor work, a getter function named <font color="#FF6600">value</font> is created to return the concatenation of the 4 input fields. Now when editing for the cell completes, the DataGrid can call upon the value property of the itemEditor and it will receive the combined fields. </p>
<p>You can also see that I have overridden the data setter function. In that function I split up the credit card number among the four TextInput fields. This is the technique you use to display the data to be edited. The editorDataField is the property used to retrieve the new value. </p>
<h3>Conclusion</h3>
  <p>In this article you've seen how to create an inline itemEditor - from simply naming a class to creating a complex class right within the MXML tags. By naming the property of the editor class which contains the final editor value, the DataGrid can retreive the value from the editor instance and replace the current value in the data. </p>
  <p>The next article covers more complex itemEditors and editing events. </p>
]]>

</content>
</entry>
<entry>
<title>Registration Open for MAX 2008</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/05/registration_op.html" />
<modified>2008-05-28T14:42:38Z</modified>
<issued>2008-05-28T17:26:18Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14937</id>
<created>2008-05-28T17:26:18Z</created>
<summary type="text/plain"> MAX 2008 will be held in San Francisco this year and is now ready for you to register. Each year MAX has gotten bigger and better. If you haven&apos;t attended MAX, make this year your first. MAX is a...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<table width="100%" cellspacing="10" border="0">
    <tr valign="top">
      <td width="35%"><img src="http://weblogs.macromedia.com/pent/max2008_000.jpg" width="300" height="145" /></td>
      <td width="65%"><p><strong><font color="#FF6600">MAX 2008</font></strong> will be held in San Francisco this year and is now ready for you to register. 
          
          </p>
        <p>Each year MAX has gotten bigger and better. If you haven't attended MAX, make this year your first. MAX is a great place to network and to see the new things coming from Adobe and other companies. MAX is also the place to meet the Adobe staff and there are always plenty of Adobe people on hand.        </p></td>
    </tr>
  </table>
    <p>Following this link and make your reservation: <a href="http://max.adobe.com/blog/">http://max.adobe.com/blog/</a> </p>
    <p><strong>Hope to see you at MAX!</strong></p>
]]>

</content>
</entry>
<entry>
<title>Return to Normal</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/05/return_to_norma.html" />
<modified>2008-05-07T20:03:25Z</modified>
<issued>2008-05-07T20:02:03Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14906</id>
<created>2008-05-07T20:02:03Z</created>
<summary type="text/plain">Our blogging server is back and my blog, along with a bushel of others, have been restored. Now I can work on my back-log of articles....</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>General Interest</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<p>Our blogging server is back and my blog, along with a bushel of others, have been restored.</p>

<p>Now I can work on my back-log of articles.</p>]]>

</content>
</entry>
<entry>
<title>Adobe Media Player</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/04/adobe_media_pla.html" />
<modified>2008-04-09T21:40:02Z</modified>
<issued>2008-04-09T22:38:54Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14868</id>
<created>2008-04-09T22:38:54Z</created>
<summary type="text/plain">Adobe Media Player,AIRAdobe&apos;s just released a new product- the Adobe Media Player. This application is built upon AIR using the Flex 3 SDK. The AMP is a new type of video player. As I write this I&apos;m watching an episode...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>AIR (Apollo)</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<!-- #BeginTags --><p class="tags"><a href="http://www.technorati.com/tag/Adobe Media Player" rel="tag">Adobe Media Player</a>,<a href="http://www.technorati.com/tag/AIR" rel="tag">AIR</a></p><!-- #EndTags --><p>Adobe's just released a new product- the <font color="#FF6600"><strong>Adobe Media Player</strong></font>. This application is built upon AIR using the Flex 3 SDK. The AMP is a new type of video player. </p>
  <p>As I write this I'm watching an episode of Star Trek: The Original Series from January 1968. It looks terrific and streams smoothly. There are a dozens of shows to choose from. </p>
  <p>I personally think this is paving the way for the future of home entertainment. Why be at the mercy of the cable or satellite companies when the content you want to watch is available when you want to watch it. Right now you can download movies from iTunes and Amazon Unbox. NBC and FOX have the <a href="http://www.hulu.com">Hulu</a> joint venture with movies and TV shows. I haven't rented a movie at a movie rental store in who-knows-how-long. </p>
  <p>For me, the problem is making the interface to these services as easy as bringing up the guide on my TiVo and as simple to connect all the boxes together.</p>
  <p>Here's an excerpt from the announcement: </p>
  <p> It [AMP] provides high  quality video playback of streamed, downloaded, or locally stored Internet TV  shows and video podcasts. Users can subscribe to Internet television shows and  other online video content, have them download automatically in the background,  and later view them on demand. AMP's user interface optimizes the user  experience, allowing users to easily enjoy finding and viewing their favorite  shows.</p>
  <p> AMP represents a tool  that is not only important to consumers, but publishers who want to monetize  advertisements. &#160;The last couple of months we have been working very hard  to get the top broadcasters signed to provide content through AMP. We have  successfully signed CBS, MTV and Food Network as just a few that will be part  of our launch. </p>
  <p><a href="http://www.adobe.com/go/getmp">Download Adobe Media Player</a> today! <br/>
    </p>
]]>

</content>
</entry>
<entry>
<title>itemRenderers: Part 5: Efficiency</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/04/itemrenderers_p_4.html" />
<modified>2008-04-02T16:50:55Z</modified>
<issued>2008-04-02T16:50:49Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14844</id>
<created>2008-04-02T16:50:49Z</created>
<summary type="text/plain">Flex,itemRenderers,AIR,UIComponent If you are displaying a large number of itemRenderers - either in the DataGrid or AdvancedDataGrid - your application&apos;s performance may be adversely affected if you do not code these itemRenderers effeciently. Here are some tips that might help:...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Components</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<!-- #BeginTags --><p class="tags"><a href="http://www.technorati.com/tag/Flex" rel="tag">Flex</a>,<a href="http://www.technorati.com/tag/itemRenderers" rel="tag">itemRenderers</a>,<a href="http://www.technorati.com/tag/AIR" rel="tag">AIR</a>,<a href="http://www.technorati.com/tag/UIComponent" rel="tag">UIComponent</a></p><!-- #EndTags -->
<p>If you are displaying a large number of itemRenderers - either in the DataGrid or AdvancedDataGrid - your application's performance may be adversely affected if you do not code these itemRenderers effeciently. Here are some tips that might help:</p>
<ul>
  <li>Limit the number of columns using itemRenderers. Do you really need to have <strong>every</strong> column be a custom itemRenderer? Sometimes you do, but is all that glitz overwhelming the user?</li>
  <li>Try not to change the style of the elements in your itemRenderer too frequenty. If you need to switch styles (eg, green for positive values, red for negative values), consider having 2 controls preset with those styles and making one visible. Changing styles is one of the more time-consuming tasks in Flex. </li>
  <li>Do not use Containers as the basis for your itemRenderers. Containers have a lot of overhead. They are fine for limited use, but it would be more efficient to write your itemRenderers based on UIComponent.</li>
</ul>
<h3>Switching Styles </h3>
<p>Here's an itemRenderer which switches components depending on the value of the data field.</p>
<pre>&lt;mx:Canvas&gt;
    &lt;mx:Script&gt;&lt;![CDATA
        <font color='#f46d0a'>private</font> <font color='#f46d0a'>function</font> lessThanZero() : Boolean {
           <font color='#f46d0a'>return</font> data.price &lt; 0;
        }
    ]]&gt;&lt;/mx:Script&gt;
    &lt;mx:Label text="{data.price}" color="#FF0000" visible="{lessThanZero()}" /&gt;
    &lt;mx:Label text="{data.price}" color="#00FF00" visible="{!lessThanZero()}" /&gt;
&lt;/mx:Canvas&gt;</pre>
<p> This will be faster than setting the style.  Some other things to keep in mind:</p>
<ul>
  <li>Avoid data binding to styles. Not only is changing styles slower than most operations, adding data binding code on top of it just makes it worse.</li>
  <li>Use a Canvas or extend ListItemRenderer or as the root of the itemRenderer. This allows you to place controls on top of each other.</li>
  </ul>
<h3>Extending UIComponent</h3>
<p>By far the most efficient way to write an itemRenderer is to extend UIComponent using an ActionScript class. You'll have complete control of the code and the renderer will be as efficient as possible.</p>
<p>Let's start with the example above, switching styles, and write a simple itemRenderer extending UIComponent.  </p>
<pre>package renderers
{
	<font color='#f46d0a'>import</font> mx.controls.listClasses.IListItemRenderer;
	<font color='#f46d0a'>import</font> mx.core.UIComponent;

	<font color='#f46d0a'>public</font> <font color='#f46d0a'>class</font> PriceItemRenderer <font color='#f46d0a'>extends</font> UIComponent <font color='#f46d0a'>implements</font> IListItemRenderer
	{
		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> PriceItemRenderer()
		{
			super();
		}
		
	}
}</pre>
<p>You'll notice that not only did I write the class to extend UIComponent, I also have it implementing the IListItemRenderer interface. It is necessary to do this because a list control will expect any renderer to implement this interface and if you do not, you'll get a runtime error as the list attempts to cast the renderer to this interface.</p>
<p>If you read the documentation on IListItemRenderer you'll see that is an amalgamation of many other interfaces, most of which UIComponent implements for you. But there is one interface extended by IListItemRenderer that UIComponent does not implement: IDataRenderer. This requires you to add the code to give the itemRenderer class the data property you've been using all along. </p>
<p>If you attempt to use this class without implementing IDataRenderer you'll get these errors when you compile the code:</p>
<p>  1044: Interface method get data in namespace mx.core:IDataRenderer not implemented by class renderers:PriceItemRenderer.	<br />
  1044: Interface method set data in namespace mx.core:IDataRenderer not implemented by class renderers:PriceItemRenderer.	<br />
</p>
<p>Edit this class and change it to the following:</p>
<pre>package renderers
{
	import mx.controls.listClasses.IListItemRenderer;
	import mx.core.UIComponent;
	import mx.events.FlexEvent;


	public class PriceItemRenderer extends UIComponent implements IListItemRenderer
	{
		public function PriceItemRenderer()
		{
			super();
		}
		
		<font color='#f46d0a'>// Internal variable for the property value.
	    private var _data:Object;
	    
	    // Make the data property bindable.
	    [Bindable("dataChange")]
	    
	    // Define the getter method.
	    public function get data():Object {
	        return _data;
	    }
	    
	    // Define the setter method, and dispatch an event when the property
	    // changes to support data binding.
	    public function set data(value:Object):void {
	        _data = value;
	    
	        dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
	    }</font>
		
	}
}</pre>
<p> I took the code directly from the Flex documentation for IDataRenderer, so you don't even have to type it yourself. </p>
<p>With that out of the way we can add in the two labels.</p>
<ol>
  <li>Add variables to hold the two labels.
    <pre>		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> posLabel:Label;
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> negLabel:Label;</pre>
</li>
  <li>Modify the set data function to call invalidateProperties(). This is important because the change of the data has to make the text in the labels change AND to change their visibility. 
    <pre>	    <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data(value:Object):void {
	        _data = value;
	    
	    	invalidateProperties();
	        dispatchEvent(<font color='#f46d0a'>new</font> FlexEvent(FlexEvent.DATA_CHANGE));
	    }</pre>
Calling invalidateProperties() tells the Flex framework to call the commitProperties() function at the apppriate time.</li>
  <li>Override createChildren() and create the labels, adding them to the display list of the component.
    Notice that in addition to creating the labels, their styles and visible are also set.
    <pre>		<font color='#f46d0a'>override</font> <font color='#f46d0a'>protected</font> <font color='#f46d0a'>function</font> createChildren() : void
		{
			super.createChildren();
			
			posLabel = <font color='#f46d0a'>new</font> Label();
			posLabel.visible = <font color='#f46d0a'>false</font>;
			posLabel.setStyle("color", 0x00FF00);
			addChild(posLabel);
			
			negLabel = <font color='#f46d0a'>new</font> Label();
			negLabel.visible = <font color='#f46d0a'>false</font>;
			negLabel.setStyle("color", 0xFF0000);
			addChild(negLabel);
		}</pre>
</li>
  <li>Override commitProperties() to set the labels' text and visibility.
    In the past you've been overriding set data to make this type of change, and you can do that in this class, too, if you prefer.
    <pre>		<font color='#f46d0a'>override</font> <font color='#f46d0a'>protected</font> <font color='#f46d0a'>function</font> commitProperties():void
		{
			super.commitProperties();
	        posLabel.text = data.price;
	        negLabel.text = data.price;
	        
	        posLabel.visible = Number(data.price) &gt; 0;
	        negLabel.visible = Number(data.price) &lt; 0;
		}</pre>
</li>
  <li>Override updateDisplayList() to size and position the labels.
    You must size the labels because their default size is 0x0. This is another thing a Container class will do for you. Since this is a pretty simple itemRenderer you can just set the labels' size to match the size of the itemRenderer.
    <pre>		<font color='#f46d0a'>override</font> <font color='#f46d0a'>protected</font> <font color='#f46d0a'>function</font> updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ) : void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			posLabel.move(0,0);
			posLabel.setActualSize(unscaledWidth,unscaledHeight);
			
			negLabel.move(0,0);
			negLabel.setActualSize(unscaledWidth, unscaledHeight);
		}</pre>
</li>
  </ol>
<p>All this probably seems a bit complicated just to do this, but keep in mind that using a container will add a lot more code than this.  </p>
<h3>UIComponent Notes</h3>
<p>The UIComponent class is the basis for all visual Flex components - controls and containers. Here are some tips about using UIComponent as your itemRenderer. </p>
<ul>
  <li>UIComponent imposes no layout restrictions on its children (unlike a Container). You have to position and size the children yourself. </li>
  <li>It is also possible to draw graphics and position children beyond the size specified in updateDisplayList().</li>
  <li>If you plan on using variableRowHeight in your list, you should also override the measure() function to give the list an idea of how big the itemRenderer is. </li>
  <li>To use UIComponent as an itemRenderer you must implement IDataRenderer.</li>
  <li>To use the listData property you must implement IDropInListItemRenderer; that was covered in a previous article of this series. </li>
</ul>
<p><br/>
</p>
]]>

</content>
</entry>
<entry>
<title>itemRenderers: Part 4: States and Transitions</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p_3.html" />
<modified>2008-03-27T21:22:47Z</modified>
<issued>2008-03-27T21:22:43Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14827</id>
<created>2008-03-27T21:22:43Z</created>
<summary type="text/plain">itemRenderer,Flex,states,transitions Communicating the with the user of your application is what your itemRenderer does best. Sometimes that communication is as simple as presenting a name; sometimes more elborately using colors; and sometimes with interactivity. itemEditors are truely interactive controls, but...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Flex 2</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<!-- #BeginTags --><p class="tags"><a href="http://www.technorati.com/tag/itemRenderer" rel="tag">itemRenderer</a>,<a href="http://www.technorati.com/tag/Flex" rel="tag">Flex</a>,<a href="http://www.technorati.com/tag/states" rel="tag">states</a>,<a href="http://www.technorati.com/tag/transitions" rel="tag">transitions</a></p><!-- #EndTags -->
  <p>Communicating the with the user of your application is what your itemRenderer does best. Sometimes that communication is as simple  as presenting a name; sometimes more elborately using colors; and sometimes with interactivity.</p>
  <p>itemEditors are truely interactive controls, but they are not the focus of this article. In these examples we'll look at itemRenderers that change their visual appearance based on either the data itself or the user's actions.</p>
  <h3>States</h3>
  <p>The Flex &lt;mx:State&gt; is a very good way to change the appearance of an itemRenderer. States are easy to use, and when combined with Transitions, give the user feedback and pleasent experience.</p>
  <p>In this example we'll create a new MXML itemRenderer (and remember, you can do this completely in ActionScript if you prefer) for the List. All this shows is the image, title, author, price, and a Button to purchase the book.</p>
  <pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" &gt;

	&lt;mx:Image id="bookImage" source="{data.image}" /&gt;
	&lt;mx:VBox height="115" width="100%" verticalAlign="top" verticalGap="0" paddingRight="10"&gt;
		&lt;mx:Text text="{data.title}" fontWeight="bold" width="100%"/&gt;
		&lt;mx:Label text="{data.author}" /&gt;
		&lt;mx:HBox id="priceBox" width="100%"&gt;
			&lt;mx:Label text="{data.price}" width="100%"/&gt;
			&lt;mx:Button label="Buy" /&gt;
		&lt;/mx:HBox&gt;
	&lt;/mx:VBox&gt;
&lt;/mx:HBox&gt;
  </pre>
  <p>What we want however, is if the book is not in stock (the data has &lt;instock&gt; nodes which are either yes or no) for the price and Book to be invisible. I've made things a bit convenient for myself here because I gave the HBox parent of the price and Button an id. This allows me to change the visibility of both of those items by changing the visibility of the HBox, priceBox.</p>
  <p>You can do this by overridding the set data function, which we'll do, but instead of directly changing the visibility of priceBox, we'll use this state defintion:</p>
  <pre>	&lt;mx:states&gt;
		&lt;mx:State name="NoStockState"&gt;
			&lt;mx:SetProperty target="{priceBox}" name="visible" value="<font color='#f46d0a'>false</font>"/&gt;
		&lt;/mx:State&gt;
	&lt;/mx:states&gt;</pre>
<p><em>&#160;&#160;&#160; Place this just below the root tag.</em>   </p>
  <p>This example is a bit far-fetched in that it is overly complicated to do a simple task, but it shows how to use states. There are 2 states:</p>
  <ul>
    <li>The base state - this is the normal state of a component. Components that do not use states simply have this base state. In this example, the base state has the priceBox visible property as true (the default). This is the case when instock is &quot;yes&quot;.</li>
    <li>The NoStockState - this is the state when the value of nostock is &quot;no&quot;. When this state is active the SetProperty instructions are carried out. The target determines which member of the class is in question, the name property is the name of the property to change on the target, and value is the new value for the property. </li>
    </ul>
  <p>The set data function determines which state to use by looking at the value of instock:</p>
  <pre>		<font color='#f46d0a'>override</font> <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data( value:Object ) : void
		{
			super.data = value;
			
			<font color='#f46d0a'>if</font>( data )
			{
				<font color='#f46d0a'>if</font>( data.instock == "yes" ) 
					currentState = "";
				else
					currentState = "NoStockState";
			}
		}</pre>
<p>The currentState is a property of all UIComponent controls. It determines which State is the active one. When switching between states the Flex framework begins with the base state and then applies the rules for the given state. </p>
<blockquote>
  <p>Remember that itemRenderers are recycled, so you must always restore values; never leave an if without an else in an itemRenderer.</p>
</blockquote>
<p>If you are feeling adventurous, you can do away with the set data override in this example. Instead, set currentState directly in the root tag by using data binding expression:  </p>
<pre>&lt;mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" 
       currentState="{data.instock == 'yes' ? '' : 'NoStockState'}" &gt;</pre>
<p>The currentState's value is set by examining data.instock right inline with the root tag. A nice trick, but it might be harder to maintain. </p>
<h3>Adding Elements</h3>
<p>In this itemRenderer the price and Buy button appears only if the instack value is yes. You could do this without a state of course, but if your itemRenderer has more controls to be added or removed, a state will make more sense as their appearance is controlled simply by setting the itemRenderer's currentState property. </p>
<p>Instead of just removing the price and Button, we'll have the state add a label telling the user the item is out of stock. Here's the modified state:</p>
<pre>	&lt;mx:states&gt;
		&lt;mx:State name="NoStockState"&gt;
			&lt;mx:SetProperty target="{priceBox}" name="visible" value="<font color='#f46d0a'>false</font>"/&gt;
			<font color='#f46d0a'>&lt;mx:AddChild relativeTo="{priceBox}" position="before"&gt;
				&lt;mx:Label text="-- currently not in stock --" color="#73DAF0"/&gt;
			&lt;/mx:AddChild&gt;</font>
		&lt;/mx:State&gt;
	&lt;/mx:states&gt;</pre>
<p>The &lt;mx:AddChild&gt; tag says to add the Label into the priceBox. In addition to setting the priceBox's visible property to false, a friendly message replaces it.</p>
<p>Again, you could add this label in the set data function - or add it initially and just set its visibility to false and change it to true in the set data function. But I think you can see the value of the State: if the requirement for the instock being no condition gets more complex, all you need to do is adjust the NoStockState; the ActionScript code which switches the state remains the same.</p>
<blockquote>
  <p>You can modify states in Flex Builder's Design View.  </p>
</blockquote>
<h3>Expanding List</h3>
  <p>This example does not work well for list controls but does perform nicely for a VBox and Repeater. This question of expanding an item in place becomes dicy when the list has to be scrolled. Imagine this: you've got a list of items will all the same height. Now you exand the height of item 2. So far so good - item 2 is taller than the other <em>visible</em> items. And there's the catch: the visible items. Now scroll the list. Remember that itemRenderers are recycled. So when item 2 scrolls out of view, its itemRenderer will be moved to the bottom of the list. You've got to reset its height. OK, that can work pretty simply. Now scroll the list so item 2 is back in view. You would expect it to be the expanded height. How does the itemRenderer know to do that? From previous articles you know that information either comes from the data itself or from some external source. </p>
  <p>I  think a resizing itemRenderer is too complex and not really worth the effort. I believe there is a better way to do this using VBox and Repeater. However, the catch with Repeater is that <strong>every</strong> child will be created. If you have 1,000 records and use a Repeater you will get 1,000 instances of your itemRenderer. </p>
  <p>For this example you'll still write an itemRenderer but will use it as the child of a VBox.&#160; The elements of a list look pretty simple: the name of a book and its author. But click the itemRenderer and it expands in place. This is accomplished using:</p>
  <ul><li>The itemRenderer has a state which includes the additional information.</li>
    <li>The itemRenderer uses a Resize transition to give a smoother expansion and contraction of the itemRenderer.</li>
    </ul>
  <p>The base state of the itemRenderer is pretty simple:       </p>
  <pre>	&lt;mx:HBox width="100%"&gt;
		&lt;mx:Label text="{data.author}" fontWeight="bold"/&gt;
		&lt;mx:Text  text="{data.title}" width="100%" fontSize="12" selectable="<font color='#f46d0a'>false</font>"/&gt;
	&lt;/mx:HBox&gt;</pre>
<p>The ExpandedState adds the additional elements which contribute to the itemRenderer's height:</p>
  <pre>	&lt;mx:states&gt;
		&lt;mx:State name="ExpandedState"&gt;
			&lt;mx:AddChild position="lastChild"&gt;
				&lt;mx:HBox width="100%"&gt;
					&lt;mx:Image source="{data.image}"/&gt;
					&lt;mx:Spacer width="100%"/&gt;
					&lt;mx:Label text="{data.price}"/&gt;
					&lt;mx:Button label="Buy"/&gt;
				&lt;/mx:HBox&gt;
			&lt;/mx:AddChild&gt;
		&lt;/mx:State&gt;
	&lt;/mx:states&gt;</pre>
<p>Getting the itemRenderer to change size is as simple as adding a Transition:</p>
<pre>	&lt;mx:transitions&gt;
		&lt;mx:Transition fromState="*" toState="*"&gt;
			&lt;mx:Resize target="{this}" /&gt;
		&lt;/mx:Transition&gt;
	&lt;/mx:transitions&gt;</pre>
<p><em>&#160;&#160;&#160; Place this below the &lt;mx:states&gt;</em></p>
<p>The Transition is applied whenever the state changes because its fromState and toState properties are wildcards. Now all you have to do is add event handler for clicking on the itemRenderer (add a click event to the root tag) and change the state:</p>
<pre>	&lt;mx:Script&gt;
	&lt;![CDATA[
		
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>function</font> expandItem() : void
		{	
			<font color='#f46d0a'>if</font>( currentState == "ExpandedState" )
				currentState = "";
			else
				currentState = "ExpandedState";
		}
	]]&gt;
	&lt;/mx:Script&gt;</pre>
<h3>Summary</h3>
<p>States are a great way to make a number of modifications to the visual appearance of the itemRenderer. You can group the changes in a State and simply make it all happen by setting the currentState property of the itemRenderer. </p>
<p>In the next article we'll look at  writing more efficient itemRenderers by extending UIComponent. <br/>
    </p>
]]>

</content>
</entry>
<entry>
<title>Viewing PDFs with AIR</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/03/viewing_pdfs_wi.html" />
<modified>2008-03-25T15:30:56Z</modified>
<issued>2008-03-25T15:30:51Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14819</id>
<created>2008-03-25T15:30:51Z</created>
<summary type="text/plain">AIR,file,filesystem,PDF One of the nice things AIR allows is the ability to view both HTML and PDF content. Here&apos;s a little app that shows how you can view PDF documents on the local computer. The key is the flash.html.HTMLLoader class....</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>

<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<!-- #BeginTags --><p class="tags"><a href="http://www.technorati.com/tag/AIR" rel="tag">AIR</a>,<a href="http://www.technorati.com/tag/file" rel="tag">file</a>,<a href="http://www.technorati.com/tag/filesystem" rel="tag">filesystem</a>,<a href="http://www.technorati.com/tag/PDF" rel="tag">PDF</a></p><!-- #EndTags -->
  <p>One of the nice things AIR allows is the ability to view both HTML and PDF content. Here's a little app that shows how you can view PDF documents on the local computer.</p>
  <p> The key is the flash.html.HTMLLoader class. This is a FLASH class and cannot be directly used with Flex components as it extends Sprite and does not implement the Flex IUIComponent interface.</p>
  <p>This is easy to remedy though. Just create a new class that extends UIComponent (I called mine PDFViewer) and include an HTMLLoader member. Override createChildren() to make a new HTMLLoader instance and add it to the UIComponent's display list. Then override updateDisplayList to size and position it.</p>
  <p align="center"><img src="http://weblogs.macromedia.com/pent/screenshot.jpg" width="290" height="225" /></p>
  <p>The main AIR application uses a FileSystemTree to allow the user to navigate to their PDF files and select one. The file's URL is passed to the PDFViewer which then loads it and displays it.  </p>
  <p>And that's pretty much it. There are some caveats to use PDF with AIR which you can read in the documentation, but if you want to use PDFs for help/documentation on your product or to display a PDF generated by a server (eg, ColdFusion), it is pretty easy to do.</p>
  <blockquote>
    <p><a href="http://weblogs.macromedia.com/pent/PDFExamples.zip">Download Example Code</a> <br/>
    </p>
  </blockquote>
]]>

</content>
</entry>
<entry>
<title>itemRenderers: Part 3: Communication</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p_2.html" />
<modified>2008-03-14T15:25:36Z</modified>
<issued>2008-03-14T15:25:31Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14795</id>
<created>2008-03-14T15:25:31Z</created>
<summary type="text/plain">Flex,itemRenderer,listData In the previous article of this series I showed you how to make external itemRenderers in both MXML and ActionScript. In the examples I&apos;ve been using there is a Button which dispatches a custom event - BuyBookEvent - so...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Components</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<!-- #BeginTags --><p class="tags"><a href="http://www.technorati.com/tag/Flex" rel="tag">Flex</a>,<a href="http://www.technorati.com/tag/itemRenderer" rel="tag">itemRenderer</a>,<a href="http://www.technorati.com/tag/listData" rel="tag">listData</a></p><!-- #EndTags -->
  <p>In <a href="http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p_1.cfm">the previous article</a> of this series I showed you how to make external itemRenderers in both MXML and ActionScript. In the examples I've been using there is a Button which dispatches a custom event - BuyBookEvent - so the application can react to it. This article covers communication with itemRenderers in more detail.</p>
  <p><font color="#FF6600">There is a rule I firmly believe must never be violated</font>: you should not get hold of an instance of an itemRenderer and change it (setting public properties) or call its public methods. This, to me, is a big no-no. The itemRenderers are hard to get at for a reason which I talked about in the <a href="http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p.cfm">first article</a>: the itemRenderers are recycled. Grabbing one breaks the Flex framework.</p>
  <p>With that rule in mind, here are things you can do with an itemRenderer:</p>
  <ul>
    <li>An itemRenderer can dispatch events via its list owner (you've seen bubbling, this is a better practice which you'll see below).</li>
    <li>An itemRenderer can use static class members. This includes Application.application. If you have values stored &quot;globally&quot; on your application object, you can reach them that way.</li>
    <li>An itemRenderer can use public members of the list which owns it. You'll see this below. </li>
    <li>An itemRenderer can use anything in the data record. You might, for example, have an item in a record that's not for direct display but which influences how an itemRenderer behaves.  </li>
    </ul>
  <h3>Dynamically Changing the itemRenderer</h3>
  <p>Here is the MXML itemRenderer from the previous article used for a TileList. We're going to make it bit more dynamic by having it react to changes from an external source (I called this file BookItemRenderer.mxml):</p>
  <pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="250" height="115" &gt;
	
	&lt;mx:Script&gt;
	&lt;![CDATA[		
	]]&gt;
	&lt;/mx:Script&gt;
	
	&lt;mx:Image id="bookImage" source="{data.image}" /&gt;
	&lt;mx:VBox height="115" verticalAlign="top" verticalGap="0"&gt;
		&lt;mx:Text text="{data.title}" fontWeight="bold" width="100%"/&gt;
		&lt;mx:Spacer height="20" /&gt;
		&lt;mx:Label text="{data.author}" /&gt;
		&lt;mx:Label text="Available {data.date}" /&gt;
		&lt;mx:Spacer height="100%" /&gt;
		&lt;mx:HBox width="100%" horizontalAlign="right"&gt;
			&lt;mx:Button label="Buy" fillColors="[0x99ff99,0x99ff99]"&gt;
				&lt;mx:click&gt;
				&lt;![CDATA[
					<font color='#f46d0a'>var</font> e:BuyBookEvent = <font color='#f46d0a'>new</font> BuyBookEvent();
					e.bookData = data;
					dispatchEvent(e);
				]]&gt;
				&lt;/mx:click&gt;
			&lt;/mx:Button&gt;
		&lt;/mx:HBox&gt;
	&lt;/mx:VBox&gt;
	
&lt;/mx:HBox&gt;
  </pre>
<p>Suppose you are showing a catalog of items in a TileList. You also have a Slider (not part of the itemRenderer) which lets the user give a range of prices; all items which fall outside of the range should fade out (the itemRenderers' alpha value should change). You need to tell each itemRenderer that the criteria has changed so that they can modify their alpha values.</p>
  <p>Your override of set data might look something like this:</p>
  <pre>override <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data( value:Object ) : void
{
    super.data = value;
    <font color='#f46d0a'>if</font>( data.price &lt; <b>criteria</b> ) alpha = 0.4;
    else alpha = 1;
}</pre>
  <p>The question is: how to change the value for criteria? The &quot;best practice&quot; for itemRenderers is to always have them work on the data they are given. In this case, it is unlikely, and impractical, to have the test criteria be part of the data. So that leaves a location outside of the data:</p>
  <ul>
    <li>Part of the list itself. That is, your list (List, DataGrid, TileList, etc) could be a class that extends a list control and which has this criteria as a public member.</li>
    <li>Part of the application as global data.</li>
  </ul>
  <p>For me, the choice is the first one: extend a class and make the criteria part of that class. After all, the class is being used to display the data, the criteria is part of that display. For this example, I would extend TileList and have the criteria as a public data member. </p>
  <pre>package
{
	
	<font color='#f46d0a'>import</font> mx.controls.TileList;
	
	<font color='#f46d0a'>public</font> <font color='#f46d0a'>class</font> CatalogList <font color='#f46d0a'>extends</font> TileList
	{
		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> CatalogList()
		{
			super();
		}
		
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> _criteria:Number = 10;
		
		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> get critera() : Number
		{
			<font color='#f46d0a'>return</font> _criteria;
		}
		
		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set criteria( value:Number ) : void
		{
			_criteria = value;
		}		
	}
}</pre>
  <p>The idea is that  a control outside of the itemRenderer can modify the criteria by changing this public property on the list control. </p>
  <h3>listData </h3>
  <p>The itemRenderers have access to another piece of data: information about the list itself and which row and column (if in a column-oriented control) they are rendering. This is known as <font color="#FF6600">listData</font> and it could be used like this in the BookItemRenderer.mxml itemRenderer example:</p>
  <pre>override <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data( value:Object ) : void
{
    super.data = value;
    <font color='#f46d0a'>var</font> criteria:Number = (<b>listData.owner</b> as MyTileList).criteria;
    <font color='#f46d0a'>if</font>( data.price &lt; criteria ) alpha = 0.4;
    else alpha = 1;
}</pre>
  <p align="center"><em>&#160;&#160;&#160; Place this code into the &lt;mx:Script&gt; block in the example BooktItemRenderer.mxml code, above. </em></p>
  <p>The listData property of the itemRenderer has an <font color="#FF6600">owner</font> field which is the control to which the itemRenderer belongs. In this example, it is the MyTileList - my extension of TileList - which is the owner. Casting the owner field to MyTileList allows the criteria to be fetched.</p>
  <h3>IDropInListItemRenderer</h3>
  <p>Access to listData is available when the itemRenderer class implements the IDropInListItemRenderer interface. Unfortunately, UI container components do not implement the interface which gives access to the listData. Control component such as Button and Label do, but for containers you have to implement the interface yourself. </p>
  <p>Implementing this interface is straightforward and found in the Flex documentation. Here's what you have to do for our BookItemRenderer class:</p>
  <ol><li>Have the class implement the interface.
      <pre>&lt;mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" ... <font color='#f46d0a'>implements="mx.controls.listClasses.IDropInListItemRenderer"</font>&gt;</pre>
</li>
    <li>Add the set and get functions to the &lt;mx:Script&gt; block in the itemRenderer file.
      <pre>		<font color='#f46d0a'>import</font> mx.controls.listClasses.BaseListData;
	
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> _listData:BaseListData;
		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> get listData() : BaseListData
		{
			<font color='#f46d0a'>return</font> _listData;
		}
		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set listData( value:BaseListData ) : void
		{
			_listData = value;
		}</pre>
</li>
    </ol>
  <p>When the list control sees that the itemRenderer implements the IDropInListItemRenderer interface it will create a listData item and assign it to every itemRenderer instance. </p>
  <h3>invalidateList()</h3>
  <p>Setting the criteria in my class isn't as simple as assigning a value. Doing that won't tell the Flex framework that the data has been changed. The change to the criteria must trigger an event. Here's the modification to the set criteria function:</p>
  <pre>		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set criteria( value:Number ) : void
		{
			_criteria = value;
			
			<b>invalidateList();</b>
		}</pre>
<p>Notice that once the _criteria value has been set it calls <font color="#FF6600">invalidateList()</font>. This causes all of the itemRenderers to be reset with values from the dataProvider and have their set data functions called. </p>
<p>The process then looks like this:</p>
<ol>
  <li>The itemRenderer looks into its list owner for the criteria to use to help it determine how to render the data.</li>
  <li>The list owner class, and extension of one of the Flex list classes, contains public properties read by the itemRenderer(s) and set by external code - another control or ActionScript code (perhaps as the result of receiving data from a remote call).</li>
  <li>When the list's property is set it calls the list's invalidateList() method. This triggers a refresh of the itemRenderers, causing them to have their data reset (and back to step 1). </li>
  </ol>
<h3>Events</h3>
<p>In the previous articles I showed how to use event bubbling to let the itemRenderer communicate with the rest of the application. I think this  is certainly quick. But I also think there is a better way, one which fits the assumption that an itemRenderer's job is to present data and the control's job is to handle the data.</p>
<p>The idea of the MyTileList control is that it is the visual - the view - of the catalog of books for sale. When a user picks a book and wants to buy it, it should be the responsibility of the list control to communicate that information to the application. In other words:</p>
<pre>&lt;CatalogList bookBuy="addToCart(event)" /&gt;</pre>
<p>The way things are set up right now, the event bubbles up and bypasses the TileList. The bubbling approach doesn't assoicate the event (bookBuy) with the list control (TileList), allowing you to move the control to other parts of your application. For instance, if you code the event listener for bookBuy on the main Application, you won't be able to move the list control to another part of the application. You'll have to move that event handler, too. If, on the other hand you have the event associated with the control you just move the control.</p>
<p>Look at it this way: suppose the click event on the Button wasn't actually an event dispatched by the Button but bubbled up from something inside of the button. You'd never be able to do: &lt;mx:Button click=&quot;doLogin()&quot; label=&quot;Log in&quot; /&gt; you would have to put the doLogin() function someplace else and that would make the application even harder to use. </p>
<p>I hope I've convinced you, so here's how to change the example from bubbling to dispatching from the list control.</p>
<p>First, you have to add metadata to the CatalogList control to let the compiler know the control dispatches the event:</p>
<pre>	<font color='#f46d0a'>import</font> events.BuyBookEvent;
	<font color='#f46d0a'>import</font> mx.controls.TileList;

	[Event(name="buyBook",type="events.BuyBookEvent")]
	
	<font color='#f46d0a'>public</font> <font color='#f46d0a'>class</font> CatalogList <font color='#f46d0a'>extends</font> TileList
	{</pre>
<p>Second, add a function to CatalogList to dispatch the event. This function will be called by the itemRenderer instances:</p>
<pre>		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> dispatchBuyEvent( item:Object ) : void
		{
			<font color='#f46d0a'>var</font> event:BuyBookEvent = <font color='#f46d0a'>new</font> BuyBookEvent();
			event.bookData = item;
			dispatchEvent( event );
		}
		
	}</pre>
<p>Third, change the Buy button code in the itemRenderer to invoke the function:</p>
<pre>			&lt;mx:Button label="Buy" fillColors="[0x99ff99,0x99ff99]"&gt;
				&lt;mx:click&gt;
				&lt;![CDATA[
					(listData.owner as CatalogList).dispatchBuyEvent(data);
				]]&gt;
				&lt;/mx:click&gt;
			&lt;/mx:Button&gt;</pre>
<p>Now the Button in the itemRenderer can simply invoke a function in the list control with the data for the record (or anything else that is appropriate for the action) and pass the responsibility of interfacing with the rest fo the application onto the list control.</p>
<p>The list control in this example dispatches an event with the data. The application can add event listeners for this event either using ActionScript or, because of the [Event] metadata in the CatalogList.as file, MXML; using [Event] metadata makes it easier for developers to use your code. </p>
<h3>Summary</h3>
<p>itemRenderers should communicate any actions using events. Custom events allow you to pass information with the event so the consumer of the event doesn't have to reach out to the itemRenderer for any data. </p>
  <p>itemRenderers should &quot;react&quot; to changes in data by overriding their set data functions. Inside of the function they can access values in their listData.owner. They could also access data stored in a static class or in the main application via Application.application.</p>
  <p>In the next article we'll look at incorporating states into itemRenders.<br/>
    </p>
]]>

</content>
</entry>
<entry>
<title>itemRenderers: Part 2: External renderers</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p_1.html" />
<modified>2008-03-06T18:41:58Z</modified>
<issued>2008-03-06T18:41:23Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14766</id>
<created>2008-03-06T18:41:23Z</created>
<summary type="text/plain"> In Part 1 of this series I showed you how to make an inline itemRenderer. That is, an itemRenderer whose MXML tags and ActionScript code are in the same file as the list using the itemRenderer. The code is...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Components</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[  <p>In <a href="http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p.cfm">Part 1 of this series</a> I showed you how to make an inline itemRenderer. That is, an itemRenderer whose MXML tags and ActionScript code are in the same file as the list using the itemRenderer. The code is &quot;in line&quot; with the rest of the code in the file.</p>
  <p>You'll also recall that I said you should think of inline itemRenderers are being separate classes. The Flex compiler in fact extracts that inline code and makes a class for you. What we're going to do in this article is make the class ourselves. The benefit of inline itemRenderers is that the code is in the same place as the list, but that's also a drawback when the itemRenderer becomes complex.</p>
  <p>Extracting the itemRenderer into an external file has several  benefits:</p>
  <ul>
    <li>The itemRenderer can easily be used in multiple lists;</li>
    <li>the code is easier to maintain;</li>
    <li>you can use Flex Builder's Design View to sketch out the initial itemRenderer.</li>
    </ul>
  <h3>An MXML itemRenderer</h3>
  <p>From the previous article you saw there was a complex itemRenderer used for a DataGrid:</p>
  <pre>&lt;mx:DataGridColumn headerText="Title" dataField="title"&gt;
		&lt;mx:itemRenderer&gt;
			&lt;mx:Component&gt;
				&lt;mx:HBox paddingLeft="2"&gt;
					&lt;mx:Script&gt;
					&lt;![CDATA[
						<font color='#f46d0a'>override</font> <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data( value:Object ) : void {
							super.data = value;
							<font color='#f46d0a'>var</font> today:Number = (<font color='#f46d0a'>new</font> Date()).time;
							<font color='#f46d0a'>var</font> pubDate:Number = Date.parse(data.date);
							<font color='#f46d0a'>if</font>( pubDate &gt; today ) setStyle("backgroundColor",0xff99ff);
							else setStyle("backgroundColor",0xffffff);
						}
					]]&gt;
					&lt;/mx:Script&gt;
					&lt;mx:Image source="{data.image}" width="50" height="50" scaleContent="<font color='#f46d0a'>true</font>" /&gt;
					&lt;mx:Text width="100%" text="{data.title}" /&gt;
				&lt;/mx:HBox&gt;
			&lt;/mx:Component&gt;
		&lt;/mx:itemRenderer&gt;
	&lt;/mx:DataGridColumn&gt;
  </pre>
<p> The itemRenderer is based on an HBox, contains an Image and a Text, and the background color is set according to the pubDate field of the item record. You can write this same itemRenderer as an external file using these steps:</p>
<ol>
  <li>If you are using Flex Builder, create a new MXML Component file (I've named mine GridColumnSimpleRenderer, but use whatever you like) and set the root tag to be HBox. Don't worry about the size.</li>
  <li>If you are using the SDK alone, create a new MXML file (call it GridColumnSimpleRenderer.mxml) and set the root tag to be HBox.</li>
  <li>With the file open, copy everything between &lt;mx:HBox&gt; and &lt;/mx:HBox&gt;, but do not copy those tags since they are already in the file. The result should look something like this:
    <pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="300"&gt;
	&lt;mx:Script&gt;
	&lt;![CDATA[
		<font color='#f46d0a'>override</font> <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data( value:Object ) : void {
			super.data = value;
			<font color='#f46d0a'>var</font> today:Number = (<font color='#f46d0a'>new</font> Date()).time;
			<font color='#f46d0a'>var</font> pubDate:Number = Date.parse(data.date);
			<font color='#f46d0a'>if</font>( pubDate &gt; today ) setStyle("backgroundColor",0xff99ff);
			else setStyle("backgroundColor",0xffffff);
		}
	]]&gt;
	&lt;/mx:Script&gt;
	&lt;mx:Image source="{data.image}" width="50" height="50" scaleContent="<font color='#f46d0a'>true</font>" /&gt;
	&lt;mx:Text width="100%" text="{data.title}" /&gt;
&lt;/mx:HBox&gt;</pre>
</li>
  <li>Save the file.</li>
  </ol>
<p>Now modify the DataGridColumn definition by removing the inline itemRenderer and replacing it with this:</p>
<pre>&lt;mx:DataGridColumn headerText="Title" dataField="title" itemRenderer="GridColumnSimpleRenderer"&gt;</pre>
<p>Now run the application. You'll get a surprise.</p>
<p>The surprise is how tall the rows are. That's because of the presence of height=&quot;300&quot; on the itemRenderer.</p>
<h3>Determining an itemRenderer's width and height </h3>
<p>The list control always sets the itemRenderer's width. In this example, the explicit width=&quot;400&quot; is ignored. You should write your itemRenderer to assume the width will change as the user changes the column or list's width. </p>
<p>The height is a different matter. If the list has an explicit rowHeight set, it will impose that height on each row, ignoring any height you've set on the itemRenderer. However, if you set the list's variableRowHeight property to true, then the list will seriously consider the itemRenderer's height. In this example, the height is explicitly set to 300, so each row is 300 pixel's high. </p>
<p>To fix this, remove the explict height from the itemRenderer file and the application will work correctly.</p>
<h3>Dynamically Changing the itemRenderer</h3>
<p>In this example the set data function has been overridden to examine the data and set the itemRenderer's backgroundColor. This is very common. Overriding set data allows you to intercept the time when the data is being changed for a new row and you can you make style changes.</p>
<p>Common mistakes are:</p>
<ul>
  <li>Forgetting to call super.data = value; this is VITAL - failure to do this will really mess up your itemRenderer;</li>
  <li>Forgetting to reset the style(s) if any tests fail. It might be tempting to just set the color when the pubDate is in the future, but you have to remember that itemRenderers are recycled and so the else statement is very necessary.</li>
  </ul>
<h3>An ActionScript itemRenderer</h3>
<p>Now we'll write another itemRenderer, this time using an ActionScript class. In the previous article there is a TileList with this inline itemRenderer:</p>
<pre>	&lt;mx:itemRenderer&gt;
		&lt;mx:Component&gt;
			&lt;mx:HBox verticalAlign="top"&gt;
				&lt;mx:Image source="{data.image}" /&gt;
				&lt;mx:VBox height="115" verticalAlign="top" verticalGap="0"&gt;
					&lt;mx:Text text="{data.title}" fontWeight="bold" width="100%"/&gt;
					&lt;mx:Spacer height="20" /&gt;
					&lt;mx:Label text="{data.author}" /&gt;
					&lt;mx:Label text="Available {data.date}" /&gt;
					&lt;mx:Spacer height="100%" /&gt;
					&lt;mx:HBox width="100%" horizontalAlign="right"&gt;
						&lt;mx:Button label="Buy" fillColors="[0x99ff99,0x99ff99]"&gt;
							&lt;mx:click&gt;
							&lt;![CDATA[
								<font color='#f46d0a'>var</font> e:BuyBookEvent = <font color='#f46d0a'>new</font> BuyBookEvent();
								e.bookData = data;
								dispatchEvent(e);
							]]&gt;
							&lt;/mx:click&gt;
						&lt;/mx:Button&gt;
					&lt;/mx:HBox&gt;
				&lt;/mx:VBox&gt;
			&lt;/mx:HBox&gt;
		&lt;/mx:Component&gt;
	&lt;/mx:itemRenderer&gt;</pre>
<p>We'll make that into an ActionScript, external, itemRenderer. You'll need to follow these steps:</p>
<ol>
  <li>Create a new ActionScript class. Call it BookTileRenderer.as and make it extend HBox, just like the inline itemRenderer.
    <pre>package
{
	<font color='#f46d0a'>import</font> flash.events.MouseEvent;
	
	<font color='#f46d0a'>import</font> mx.containers.HBox;
	<font color='#f46d0a'>import</font> mx.containers.VBox;
	<font color='#f46d0a'>import</font> mx.controls.Button;
	<font color='#f46d0a'>import</font> mx.controls.Image;
	<font color='#f46d0a'>import</font> mx.controls.Label;
	<font color='#f46d0a'>import</font> mx.controls.Spacer;
	<font color='#f46d0a'>import</font> mx.controls.Text;
	
	<font color='#f46d0a'>public</font> <font color='#f46d0a'>class</font> BookTileRenderer <font color='#f46d0a'>extends</font> HBox
	{
		<font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> BookTileRenderer()
		{
			super();
		}
		
	}
}</pre>
</li>
  <li>Create member variables to hold the references to the child components. 
    <pre>		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> coverImage:Image;
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> titleText:Text;
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> spacer1:Spacer;
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> authorLabel:Label;
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> pubdateLabel:Label;
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> spacer2:Spacer;
		<font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> buyButton:Button;</pre>
</li>
  <li>Override the createChildren() function to create the child components and add them to the HBox.
    <pre>		<font color='#f46d0a'>override</font> <font color='#f46d0a'>protected</font> <font color='#f46d0a'>function</font> createChildren():void
		{
			coverImage = <font color='#f46d0a'>new</font> Image();
			addChild(coverImage);
			
			<font color='#f46d0a'>var</font> innerBox:VBox = <font color='#f46d0a'>new</font> VBox();
			innerBox.explicitHeight = 115;
			innerBox.percentWidth = 100;
			innerBox.setStyle("verticalAlign","top");
			innerBox.setStyle("verticalGap", 0);
			addChild(innerBox);
			
				titleText = <font color='#f46d0a'>new</font> Text();
				titleText.setStyle("fontWeight","bold");
				titleText.percentWidth = 100;
				innerBox.addChild(titleText);
			
				spacer1 = <font color='#f46d0a'>new</font> Spacer();
				spacer1.explicitHeight = 20;
				innerBox.addChild(spacer1);
			
				authorLabel = <font color='#f46d0a'>new</font> Label();
				innerBox.addChild(authorLabel);
			
				pubdateLabel = <font color='#f46d0a'>new</font> Label();
				innerBox.addChild(pubdateLabel);
			
				spacer2 = <font color='#f46d0a'>new</font> Spacer();
				spacer2.percentHeight = 100;
				innerBox.addChild(spacer2);
			
				<font color='#f46d0a'>var</font> buttonBox:HBox = <font color='#f46d0a'>new</font> HBox();
				buttonBox.percentWidth = 100;
				buttonBox.setStyle("horizontalAlign","right");
				innerBox.addChild(buttonBox);
			
					buyButton = <font color='#f46d0a'>new</font> Button();
					buyButton.label = "Buy";
					buyButton.setStyle("fillColors",[0x99ff99,0x99ff99]);
					buyButton.addEventListener(MouseEvent.CLICK, handleBuyClick);
					buttonBox.addChild(buyButton);
		}</pre>
           
           
           
           
          &#160;I've indented the code to show the parent-child relationships. Also, make sure you include an event listener on the Buy button. </li>
  <li>Override the commitProperties() function and set the user interface controls from the data.
    <pre>		<font color='#f46d0a'>override</font> <font color='#f46d0a'>protected</font> <font color='#f46d0a'>function</font> commitProperties():void
		{
			super.commitProperties();
			
			coverImage.source = data.image;
			titleText.text = data.title;
			authorLabel.text = data.author;
			pubdateLabel.text = data.date;
		}</pre>
</li>
  <li>Add the click event handler for the Buy button.
    <pre>		<font color='#f46d0a'>private</font> <font color='#f46d0a'>function</font> handleBuyClick( event:MouseEvent ) : void
		{
			<font color='#f46d0a'>var</font> e:BuyBookEvent = <font color='#f46d0a'>new</font> BuyBookEvent();
			e.bookData = data;
			dispatchEvent(e);
		}</pre>
</li>
  <li>Modify the TileList in the main application to use the itemRenderer ActionScript class. Simply remove the inlineItemRenderer and replace it with an itemRenderer property right in the tag.  
    <pre>&lt;mx:TileList id="mylist" x="29" y="542" width="694" <b>itemRenderer="BookTileRenderer"</b> 
       dataProvider="{testData.book}" height="232" columnWidth="275" rowHeight="135" &gt;</pre>
</li>
</ol>
<p>If you are going to use an existing container class, such as HBox, I wouldn't  bother doing this in ActionScript. You can see it is more complex than using an MXML file and, quite frankly, there is little performance benefit to it. </p>
<h3>Reusable itemRenderers</h3>
<p>Here's an example of an itemRenderer that displays a numeric value using the CurrencyFormatter. I call it PriceFormatter: </p>
<pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;mx:Text xmlns:mx="http://www.adobe.com/2006/mxml"&gt;

	&lt;mx:Script&gt;
		&lt;![CDATA[
			<font color='#f46d0a'>import</font> mx.controls.dataGridClasses.DataGridListData;
			
			[<font color='#f46d0a'>Bindable</font>] <font color='#f46d0a'>private</font> <font color='#f46d0a'>var</font> formattedValue:String;
			
			<font color='#f46d0a'>override</font> <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data(value:Object):void
			{
				super.data = value;
				
				<font color='#f80000'>formattedValue = cfmt.format( Number(data[(listData as DataGridListData).dataField]) );</font>
			}
		]]&gt;
	&lt;/mx:Script&gt;
	
	&lt;mx:CurrencyFormatter precision="2" id="cfmt" /&gt;
	
	&lt;mx:text&gt;{formattedValue}&lt;/mx:text&gt;
	
&lt;/mx:Text&gt;</pre>
<p>The key to this itemRenderer is shown in <font color="#FF0000">red</font>, setting the bindable variable, formattedValue. First, you'll see that &lt;mx:CurrentFormatter&gt; was defined as an MXML tag (you can do this in ActionScript, too, if you prefer) with an id of cfmt. In the example above, the formattedValue is set to the result of calling the CurrentFormatter's <font color="#FF0000">format() </font>function.</p>
<p>The function takes a Number as its parameter type, so the value is cast to <font color="#FF0000">Number</font> - that's because the dataProvider for the list is XML and everything in XML is text; if you use a Object for your data and you have real numeric values, doing the Number cast will be harmless.</p>
<p>As you know, data is the property which holds the  item being displayed by the itemRenderer. Using [ ] notation is another way of accessing the fields of the data item. For example, <font color="#FF0000">data['price']</font> would be the price column. But to make this itemRenderer resuable we cannot code for a specific field, so a more generic way is needed.</p>
<p>That's where <font color="#FF0000">listData</font> comes in. All Flex components which implement the IDropInListItemRenderer interface have a listData property.</p>
<blockquote>
  <p>Most controls such as Text, Label, Button, CheckBox, and so forth, implement IDropInListItemRenderer. Most containers, such as HBox, Canvas, etc. <strong>do not</strong> implement that interface. If you want to use listData in an itemRenderer that extends a Container you will have to implement IDropInListItemRenderer yourself - I'll cover that in the next article.  </p>
</blockquote>
<p>The listData given to an itemRenderer contains, among other things, the rowIndex and the control which owns the itemRenderer - the DataGrid, List, or TileList. When you have an itemRenderer being used for the DataGrid, the listData is actually a <font color="#FF0000">DataGridListData</font> object - which includes the columnIndex and the <font color="#FF0000">dataField</font> associated with the DataGridColumn. Here's the breakdown of the statement above, starting from the inside:</p>
<ul>
  <li><font color="#FF0000">listData as DataGridListData </font>- This casts the listData to a DataGridListData object so you have access to its dataField</li>
  <li><font color="#FF0000">.dataField </font>- the field for the column being rendered. This is what makes this itemRenderer generic. You can use this itemRenderer for multiple columns. In this example the dataField is 'price'. </li>
  <li><font color="#FF0000">data[ ... ] </font>- This accesses the data for the specific field in the item. In this example it will be the price column.  </li>
  <li><font color="#FF0000">Number( ... ) </font>- This casts the value to a Number because the format() function requires a Number parameter.</li>
  <li><font color="#FF0000">cfmt.format( ... ) </font>- This formats the value as a currency.  </li>
</ul>
<h3>Summary</h3>
<p>Use whatever makes you comfortable when implementing itemRenderers. Some people only work in ActionScript which is great when you've got experience with Flex and ActionScript. MXML makes quick work of simple itemRenderers, too. </p>
<p>In a future  article we'll look at making more efficient itemRenderers, which are ActionScript classes, but they extend UIComponent. In the next article I'll discuss more communication between itemRenderers and the rest of the application. </p>
<p><br/>
    </p>
]]>

</content>
</entry>
<entry>
<title>itemRenderers: Part 1: inline renderers</title>
<link rel="alternate" type="text/html" href="http://weblogs.macromedia.com/pent/archives/2008/03/itemrenderers_p.html" />
<modified>2008-03-03T18:58:05Z</modified>
<issued>2008-03-03T13:26:57Z</issued>
<id>tag:weblogs.macromedia.com,2008:/pent//32.14751</id>
<created>2008-03-03T13:26:57Z</created>
<summary type="text/plain">Adobe,Flex ActionScript 3,itemRenderer I&apos;m starting a new series of articles on itemRenderers. Our documentation team has great examples so please check that information out first. I&apos;m giving you my distillation of it. Recycling Renderers One thing many people try to...</summary>
<author>
<name>pent</name>
<url>http://weblogs.macromedia.com/pent/</url>
<email>pent@macromedia.com</email>
</author>
<dc:subject>Components</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.macromedia.com/pent/">
<![CDATA[<!-- #BeginTags --><p class="tags"><a href="http://www.technorati.com/tag/Adobe" rel="tag">Adobe</a>,<a href="http://www.technorati.com/tag/Flex ActionScript 3" rel="tag">Flex ActionScript 3</a>,<a href="http://www.technorati.com/tag/itemRenderer" rel="tag">itemRenderer</a></p><!-- #EndTags -->
  <p>I'm starting a new series of articles on itemRenderers. Our documentation team has great examples so please check that information out first. I'm giving you my distillation of it.</p>
  <h3>Recycling Renderers</h3>
  <p>One thing many people try to do is access an itemRenderer from outside of the list. For example, you might want to make the cell in the 4th column of the 5th row in a DataGrid turn green because you've just received new data from the server. Getting that itemRenderer instance and modifying it externally would be a huge breech of the Flex framework and component model.</p>
  <p>To understand itemRenderers you have to understand why they are what they are and what our intentions were when we designed them. BTW - when I say 'we' I really mean the Adobe Flex engineering team - I had nothing to do with it. Anyway, suppose you have 1000 records you want to show. If you think the list control creates 1000 itemRenderers you are incorrect. If the list is showing only 10 rows, the list creates about 12 itemRenderers - enough to show every visible row plus a couple for buffering and performance reasons. The list initially shows rows 1 through 10. When the user scrolls the list it may now be showing rows 3 - 12. But those same 12 itemRenderers are still there - no new itemRenderers were created, even after the list scrolled.</p>
  <p>Here's what we do. When the list is scrolled, those itemRenderers which will still be showing the same data (rows  3 - 10) are moved upward. Aside from being in a new location, they haven't changed. The itemRenderers that were showing the data for rows 1 and 2 are now moved below the itemRenderer for row 10. Then those itemRenderers are given the data for rows 11 and 12. In other words, unless you resize the list, those same itemRenderers are reused - recycled - to a new location and are now showing new data.</p>
  <blockquote>
    <p>If you want to change the background color of the cell in the 4th column of the 5th row, be aware that the itemRenderer for that cell may now be showing the contents of the 21st row if the user has scrolled the list.  </p>
  </blockquote>
  <p>So how do you make changes like this?</p>
  <p>The itemRenderers must change themselves based on the data they are given to show. If the itemRenderer for the list is supposed to change its color based on a value of the data, then it must look at the data it is given and change itself.</p>
  <h3>inline itemRenderers</h3>
  <p>In this article we'll look at the answer to this problem using inline itemRenderers. An inline itemRenderer is one which is written directly in the MXML file where the list control occurs. In the next article we'll look at writing external itemRenderers. The inline itemRenderers are the least complex and are generally used for very simple renderers or for prototyping a larger application. There's nothing wrong with inline itemRenderers, but when the code becomes complex it is better to extract it into its own class.</p>
  <p>In all of the examples we'll use the same data: a collection of information about books: author, title, publication date, thumbnail image, and so forth. Each record is an XML node which looks like this:</p>
  <pre>&lt;book&gt;
    &lt;author&gt;Peter F. Hamilton&lt;/author&gt;
    &lt;title&gt;Pandora's Star&lt;/title&gt;
    &lt;image&gt;assets/pandoras_star_.jpg&lt;/image&gt;
    &lt;date&gt;Dec 3, 2004&lt;/date&gt;
&lt;/book&gt;</pre>
<p>Let's start with a simple itemRenderer using a &lt;mx:List&gt; control. Here, the author is listed followed by the title of the book.  </p>
<pre>	&lt;mx:List x="29" y="67" dataProvider="{testData.book}" width="286" height="190"&gt;
		&lt;mx:itemRenderer&gt;
			&lt;mx:Component&gt;
				&lt;mx:Label text="{data.author}: {data.title}" /&gt;
			&lt;/mx:Component&gt;
		&lt;/mx:itemRenderer&gt;
	&lt;/mx:List&gt;</pre>
<p>This itemRenderer is so simple that a labelFunction would probably have been better, but it at least lets you focus on the important parts. First, an inline itemRenderer uses the &lt;mx:itemRenderer&gt; tag to define it. Within this tag is the &lt;mx:Component&gt; tag. This tag <strong>must</strong> be here as it tells the Flex complier you are defining a component inline. We'll discuss what this really means in a bit.</p>
<p>Within the &lt;mx:Component&gt; tag you define your itemRenderer. For this example it is a single &lt;mx:Label&gt; with its text field set to a data-binding expression: {data.author}: {data.title}. <strong>This is very important.</strong> The list control gives each itemRenderer instance the record of the dataProvider by setting the itemRenderer's data property. Looking at the code above, it means that for any given row of the list, the itemRenderer instance of its inline itemRenderer will have its data property set to a &lt;book&gt; XML node (such as the one above). As you scroll through the list, the data property is being changed as the itemRenderers are recycled for new rows. </p>
<p>In other words, the itemRenderer instance for row 1 might have its data.author set to &quot;Peter F. Hamilton&quot; now, but when it scrolls out of view, the itemRenderer will be recycled and the data property - for that same itemRenderer - may now have its data.author set to &quot;J.K. Rowling&quot;. All of this happens automatically as the list scrolls - you don't worry about it.</p>
<p> Here's a more complex inline itemRenderer using the &lt;mx:List&gt; control again:</p>
<pre>	&lt;mx:List x="372" y="67" width="351" height="190" variableRowHeight="<font color='#f46d0a'>true</font>" dataProvider="{testData.book}"&gt;
		&lt;mx:itemRenderer&gt;
			&lt;mx:Component&gt;
				&lt;mx:HBox &gt;
					&lt;mx:Image source="{data.image}" width="50" height="50" scaleContent="<font color='#f46d0a'>true</font>" /&gt;
					&lt;mx:Label text="{data.author}" width="125" /&gt;
					&lt;mx:Text  text="{data.title}" width="100%" /&gt;
				&lt;/mx:HBox&gt;
			&lt;/mx:Component&gt;
		&lt;/mx:itemRenderer&gt;
	&lt;/mx:List&gt;</pre>
<p> This really isn't much different. Instead of a &lt;mx:Label&gt; the itemRenderer is an &lt;mx:HBox&gt; with an &lt;mx:Image&gt;, &lt;mx:Label&gt;, and a &lt;mx:Text&gt; control. Data-binding still relates the visual with the record. </p>
<h3>DataGrid</h3>
<p>You can use inline itemRenderers on a DataGrid, too. Here's one applied to a column:</p>
<pre>	&lt;mx:DataGrid x="29" y="303" width="694" height="190" dataProvider="{testData.book}" variableRowHeight="<font color='#f46d0a'>true</font>"&gt;
		&lt;mx:columns&gt;
			&lt;mx:DataGridColumn headerText="Pub Date" dataField="date" width="85" /&gt;
			&lt;mx:DataGridColumn headerText="Author" dataField="author" width="125"/&gt;
			&lt;mx:DataGridColumn headerText="Title" dataField="title"&gt;
				&lt;mx:itemRenderer&gt;
					&lt;mx:Component&gt;
						&lt;mx:HBox paddingLeft="2"&gt;
							&lt;mx:Script&gt;
							&lt;![CDATA[
								<font color='#f46d0a'>override</font> <font color='#f46d0a'>public</font> <font color='#f46d0a'>function</font> set data( value:Object ) : void {
									super.data = value;
									<font color='#f46d0a'>var</font> today:Number = (<font color='#f46d0a'>new</font> Date()).time;
									<font color='#f46d0a'>var</font> pubDate:Number = Date.parse(data.date);
									<font color='#f46d0a'>if</font>( pubDate &gt; today ) setStyle("backgroundColor",0xff99ff);
									else setStyle("backgroundColor",0xffffff);
								}
							]]&gt;
							&lt;/mx:Script&gt;
							&lt;mx:Image source="{data.image}" width="50" height="50" scaleContent="<font color='#f46d0a'>true</font>" /&gt;
							&lt;mx:Text width="100%" text="{data.title}" /&gt;
						&lt;/mx:HBox&gt;
					&lt;/mx:Component&gt;
				&lt;/mx:itemRenderer&gt;
			&lt;/mx:DataGridColumn&gt;
		&lt;/mx:columns&gt;
	&lt;/mx:DataGrid&gt;</pre>
<p> As you can see, this is much more complex than the last two, but it has the same structure: &lt;mx:itemRenderer&gt; with &lt;mx:Component&gt; definition inside of it.</p>
<p>The purpose of &lt;mx:Component&gt; is to provide an MXML syntax for creating an ActionScript class right in the code. Picture the code that appears in the &lt;mx:Component&gt; block being cut out and put into a separate file and given a class name.  When you look at the inline itemRenderer it does look like a complete MXML file, doesn't it? There's the root tag (&lt;mx:HBox&gt; in this case) and even a &lt;mx:Script&gt; block.</p>
<p>The purpose of the &lt;mx:Script&gt; block in this example is to override the set data function so the background color of the itemRenderer can be changed. In this case, the background is changed from white whenever the publication data for a book is in the future. <strong>Remember that itemRenderers are recycled, so the color must also be set back to white if the test fails. Otherwise all of the itemRenderers will eventually turn purple as the user scrolls through the list. </strong> </p>
<h3>outerDocument</h3>
<p>The <em>scope</em> has also changed. What I mean is, variables that you define from within a &lt;mx:Component&gt; are only scoped to that component/inline itemRenderer. Likewise, the content outside of the &lt;mx:Component&gt; is in a different scope, just as if this component were defined in a separate file. For instance, suppose you add a Button to this itemRenderer that allows the user to by the book from an online retailer. Buttons call functions on their click event, so you might define the button like this:</p>
<pre>&lt;mx:Button label="Buy" click="buyBook(data)" /&gt;</pre>
<p> If the buyBook() function were defined in the &lt;mx:Script&gt; block of the file you would get an error saying that buyBook() is an undefined  method. That's because buyBook() is defined in the scope of the file, not in the scope of the &lt;mx:Component&gt;. Since this is a typical use case there is a way around that using the outerDocument identifier:</p>
<pre>&lt;mx:Button label="Buy" click="outerDocument.buyBook(data)" /&gt;</pre>
<p> The outerDocument identifier changes the scope to look into the file, or outer document, with reference to the &lt;mx:Component&gt;. Now beware: the function has to be a public function, not a protected or private one. Remember that &lt;mx:Component&gt; is treated as an externally defined class. </p>
<h3>Bubbling Events </h3>
<p>Let's look at another, even more complex example. This is a TileList using the same data.</p>
<pre>	&lt;mx:TileList x="29" y="542" width="694" dataProvider="{testData.book}" height="232" columnWidth="275" rowHeight="135" &gt;
		&lt;mx:itemRenderer&gt;
			&lt;mx:Component&gt;
				&lt;mx:HBox verticalAlign="top"&gt;
					&lt;mx:Image source="{data.image}" /&gt;
					&lt;mx:VBox height="115" verticalAlign="top" verticalGap="0"&gt;
						&lt;mx:Text text="{data.title}" fontWeight="bold" width="100%"/&gt;
						&lt;mx:Spacer height="20" /&gt;
						&lt;mx:Label text="{data.author}" /&gt;
						&lt;mx:Label text="Available {data.date}" /&gt;
						&lt;mx:Spacer height="100%" /&gt;
						&lt;mx:HBox width="100%" horizontalAlign="right"&gt;
							&lt;mx:Button label="Buy" fillColors="[0x99ff99,0x99ff99]"&gt;
								&lt;mx:click&gt;
								&lt;![CDATA[
									<font color='#f46d0a'>var</font> e:BuyBookEvent = <font color='#f46d0a'>new</font> BuyBookEvent();
									e.bookData = data;
									dispatchEvent(e);
								]]&gt;
								&lt;/mx:click&gt;
							&lt;/mx:Button&gt;
						&lt;/mx:HBox&gt;
					&lt;/mx:VBox&gt;
				&lt;/mx:HBox&gt;
			&lt;/mx:Component&gt;
		&lt;/mx:itemRenderer&gt;
	&lt;/mx:TileList&gt;</pre>
<p> The itemRenderer looks like this when the application is run:</p>
<p><img src="http://weblogs.macromedia.com/pent/TileListItemRenderer.jpg" width="272" height="130" /></p>
<p>This itemRenderer is pretty close to the one used in the DataGrid, but the Buy button's click event doesn't use outerDocument to call a function. In this case the click event creates a custom event which <strong>bubbles</strong> up out of the itemRenderer, through the TileList, and is received by some higher component in the visual chain. </p>
<blockquote>
  <p>This is a very common problem: you have an itemRenderer which has some interactive control in it, usually a Button, LinkButton, etc. that is supposed to cause some action to take place when clicked. Perhaps it is to delete the row or in this case, buy the book. </p>
</blockquote>
<p>It is unreasonable to expect the itemRenderer to do the work. Afterall, the itemRenderer's job is to make the list look good - period. Event bubbling allows the itemRenderer  to pass off the work to something else. A custom event is useful here because the event is related to the data on the row - so why not include that data in the event; the receiver of the event won't have to go hunt it down.</p>
<h3>Summary</h3>
<p>Using inline itemRenderers is a great and quick way to give your lists a custom look. Consider inline itemRenderers as separate ActionScript classes - afterall, they are scoped as if they were. If you must refer to functions or properties in the containing file, use the outerDocument identifier to change the scope. If you need to communicate information as the result of an interaction with the itemRenderer, use a custom, bubbling, event.</p>
<p><strong>And remember:</strong> don't try to get hold of itemRenderers - they are recycled for a purpose. Make them responsible only to the data given to them.  </p>
<p>In the next article I'll discuss external itemRenderers. <br/>
</p>
]]>

</content>
</entry>

</feed>