Tuesday, October 25, 2011

Multiple initializers for property 'dataprovider'

So, while migrating from Flex 3 to Flex 4, I'm going through the

  • change namespaces
  • move mx: to fx:
  • wrap non-UIComponents into <fx:Declarations>
The next round of compiler errors is
"Multiple initializers for property 'dataProvider'. (note: 'dataProvider' is the default property of 'mx.controls.ComboBox').

Super useful error message here. 
Thanks to the hint at http://www.freeflowingcode.com/blog/flex/flex-multiple-initializers I noticed that there where still non-visual elements inside these components. 

Wrapping these elements into <fx:Declarations> made the error go away. 

So I guess that the take-away is, for components that use a dataProvider, and whose default property is dataProvider, you get a cryptic error message when your <Declarations> are not inside the correct tag. 

Showing more errors in Flash Builder / Eclipse

Have you had a task, like repackaging, migrating from Flex 3 to Flex 4, or anything that generated 100s of errors. Did you ever notice that eclipse had a "convenient" way of displaying 100 of (x+100) errors? I just discovered the simple way to show ALL of your errors.

Problems View -> Preferences (via down arrow on right hand side) -> Use Marker Limit = false;

Tuesday, October 4, 2011

Focusing on the spark Datagrid

From my presentation at 360Flex Unconference at Max.

The Slide Deck

Here is the blog that talks about the demo and has the source code:
The demo and source code


Tuesday, September 13, 2011

Precision focus control within the Spark DataGrid

So, in preparation for my MAX 360Flex Unconference presentation on Tues Oct 4th at 2pm (http://www.360flex.com/blog/2011/08/360max-the-schedule-2/) I've put together this demo about how to get precision focus control within the Spark Datagrid.

In this example you can see:

  • Set focus to first editable item
  • Tab through occasionally editable fields
  • Focus with a mixture of multiple occasionally editable fields within a record
  • Focus on a particular data item
  • Focus using Tab, Shift+Tab, Arrows, and Page-Up and Page-Down
  • Remove Focus
  • Focus by clicking on a row
(Note, I've left the "disabled" cells editable, as I'm only changing the alpha. This is so that you can see that even if you click in to the non-editable fields directly, that the editing sessions (via the "Dashboard") doesn't get set)

view source

The slide deck for the preso will be coming soon.

Wednesday, September 7, 2011

DataGrids performance tests

 So my mission is to try to performance test the 3 Flex grids. mx:DataGrid, s:DataGrid and mx:AdvancedDataGrid.

I feel like my tests are incorrect and looking to you to point out my flaws.

Each grid has the same dataprovider and columns defined. I'm only using the default renderers
I have a StopWatch class, that will getTimer() from a start() method, until the next Event.RENDER from the grid under test.
I remove the data provider by setting it to null.
Once the screen is blank, I start the stopwatch and add the dataprovider.

The average of these tests over ten samples is:

Spark DataGrid: 207 ms
mx DataGrid: 176ms
AdvancedDataGrid: 171ms

I feel like my testing method is invalid, as I don't trust that

   1. The ADG is the fastest at rendering
   2. Spark is the worst at rendering
   3. That the difference in rendering between the 3 grids is negligible

Anyone to offer any insight?

Tuesday, August 9, 2011

HierarchicalCollectionView and Sorting Discovery

More woes around HierarchicalCollectionView. This was discovered while trying sort from the columns in the AdvancedDataGrid.

The usual case is that you click on a column and the sorting gets applied based on that column's datafield. In our case though, the datafield was a placeholder, as the item renderer took care of collecting the needed data out of the local cache based on the materialId.

Soooo... for sorting, we applied a sortCompareFunction to the column to account for this - so far so good.... until.....

HierarchicalCollectionView
 private function sortCanBeApplied(coll:ICollectionView):Boolean
    {
        if (sort == null)
            return true;
        
        // get the current item
        var obj:Object = coll.createCursor().current;
        
        if (!obj || !sort.fields)
            return false;
        
        // check for the properties (sort fields) in the current object
        for (var i:int = 0; i < sort.fields.length; i++)
        {
            var sf:SortField = sort.fields[i];
            if (!obj.hasOwnProperty(sf.name))
                return false;
        }
        return true;
    }
Notice line 16: if (!obj.hasOwnProperty(sf.name)) Well, if you trace everything back, it is essentially saying that the data HAS to have the property of the datafield of the column, otherwise no sorting.

Drat... now we have to add all of these [Transient] property placeholders to our vos, just to get sorting to work. (While messy, the other alternatives seemed even more messy and risky. Please comment if you have suggestions).

Here is a list of ideas that we considered but decided that it would make the code base less readable and understandable

  • Override hasOwnProperty on the VO
  • Override AdvancedDataGrid.addSortField() to change the sortField.name

  • Wednesday, July 27, 2011

    Spark Data Grid Tab Focus Control

    After spending so many months customizing the AdvancedDataGrid, I'm now interested to see if I can migrate many of those customizations to the Spark DataGrid. One of my first challenges is to see if I can improve my focus control - specifically tab navigation.

    To review, here is the use case I'm trying to achieve (BTW it works in spark, and only partially works in ADG). My data is a product, and I have two occasionally editable fields related to this product: Quantity and Price (my role is a sales associate - so I can negotiate on prices). The product as a whole is only editable if it is in stock; I cannot change quantity or price if it is out of stock. Price is only editable if and handful of business rules apply (margin, vendor, etc). I want to be able to tab to the editable fields.

    The problem with the ADG was that in it's "findNextEditableItemRenderer" loop, it only checked the data (ie, inStock). There was no way to tell what column it was looking at.

    I was quite pleased with the spark DataGrid and its nice separation of concerns. I love that there is a separate DataGridEditor. And I was happy to discover that there was a simple PUBLIC method on DataGrid that I could tap into to do everything that I wanted (So far).

    That public method is startItemEditorSession(rowIndex:int, columnIndex:int):Boolean. SWEET!

    That problem is resolved in the spark dataGrid.
    You can see the example here. In this example, the top grid is the regular one and the bottom grid is the modified one. I'm using the alpha property instead of enabled to prove that focus is indeed under my control (MUH HA HA HA - <evil laugh>).

    The key is that within the startItemEditorSession, you
  • convert the rowindex to the data via the getItemAt on the dataprovider
  • convert the columnIndex to the column
  • validate the data as well as the data[column.datafield] properties
  • return the boolean if editing should happen.

    And here is the code

    public class FocusSparkDataGrid extends DataGrid 
     {
      private var _isDataEditableHelper:IIsDataEditable
      
      public function FocusSparkDataGrid()
      {
       super();
      }
      
    
      public function get isDataEditableHelper():IIsDataEditable
      {
       return _isDataEditableHelper;
      }
    
      public function set isDataEditableHelper(value:IIsDataEditable):void
      {
       _isDataEditableHelper = value;
      }
    
      override public function startItemEditorSession(rowIndex:int, columnIndex:int):Boolean
      {
       var dataIsEditable:Boolean = isDataEditable(rowIndex,columnIndex);
       if (dataIsEditable)
       {
        var editingStarted:Boolean = super.startItemEditorSession(rowIndex,columnIndex);
        return editingStarted
       }
       return false;
      }
    
      
      protected function isDataEditable(rowIndex:int, columnIndex:int):Boolean
      {
       if (isDataEditableHelper != null)
       {
        var dataItem:Object = dataProvider.getItemAt(rowIndex);
        var column:GridColumn = GridColumn(columns.getItemAt(columnIndex));
        var dataField:String = column.dataField;
        return isDataEditableHelper.isDataEditableForProperty(dataItem,dataField)
       }
       return false;
      }
    }
    
    

    public class IsProductVOEditable implements IIsDataEditable
     {
      public function IsProductVOEditable()
      {
      }
      
      public function isDataEditableForProperty(data:Object, property:String=""):Boolean
      {
       var vo:ProductVO = ProductVO(data);
       if (vo.inStock)
       {
        if (property == "price")
        {
         return vo.priceEditable;
        }
        return true;
       }
       return false;
      }
     }