apache-flexactionscriptitemrendereradvanceddatagrid

ItemRenderer height (and height changes) not reflected in AdvancedDataGrid row


I have an AdvancedDataGrid with variable row height set to true. I have written a cutsom item renderer based on the DataGroup spark component. Each row in the grid has multiple entities to display, the x position and width of the entites are based on the data of the entity itself.

I have a custom layout written for the DataGroup that measures and posistions each entity based on its data. Each entity in each row can either truncate or not truncate its label. When the labels are not truncated, I calculate the actual width of the object and validate its size manualy (to force the label to have the correct width and layout all its text lines and remeasure itself) within the DataGroup's Layout's measure method to accurately measure the datagroup itself.

The layouts, measuring, sizing, display, etc all work correctly. The entitys report the correct height they need when not truncating the labels, the datagroup reports the correct size it needs to draw all of its row's worth of entities (all from measure methods like they need to under the UIComponent lifecycle).

When inside the AdvancedDataGrid itself, rows are not sized correctly. The majority of the rows do not require multiple lines and display just fine. Those that require multiple lines have larger row heights, but not large enough to accomodate the entire text in most cases. The DataGroup for that row (and its itemRenderers) are clipped. Furthermore, When scrolling the grid, every row scrolled onscreen is the default 1 text line height, irregardless of data. In any case, resizing the AdvancedDataGrid (not resizing its columns, but the grid itself) forces all rows to snap to the correct desired height. Scrolling again produces incorreclty sized rows.

Additionally, the layout of each entity in the row is determined by several external factors - most commonly being visible range (along the horizontal). Changing this visible range will trigger all item renderers to resize themselves (through the custom layout class) to their new sizes and remeasuring the new DataGroup layout. This actually triggers a custom hierarchy parser which rebuilds all the ArrayCollections used inside the AdvandedDataGrid data provider, so ArrayCollections are dispatching change events that each row's DataGroup reacts to, so the DataGroup itself is invalidating its size and layout.

These resizes do not trigger the AdvancedDataGrid to remeasure its row heights, and I must rezise the ADG itself again to snap the rows to the correct height.

Anyone have any experience with dynamically sized rows in an AdvancedDataGrid or ItemRenderers which must forcibly make the AdvandedDataGrid re-layout its rows?

Unfortunately, I cannot provide source code as there are a huge number of classes going into this, hierarchial data, rolling up closed nodes into multiple rows, custom hierarchy parsers, a multitude of item renderers - that and its a Government contract.

I have run into a similar issue with a much simpler item renderer, basically a label that will respect a max height, resize itself upto that height as its wordwrapping data will require, and then create scrollbars for itself. Again, the data sizes almost correclty when the grid is created, then changing the column width within the grid does not resize the row height as the item renderer adjusts to its new width. Only in resizing the grid itself do the item renderers resize correctly, create scroll bars, and the grids row heights are correct. The source for that item renderer:

<s:Scroller xmlns:fx="http://ns.adobe.com/mxml/2009" 
            xmlns:s="library://ns.adobe.com/flex/spark" 
            xmlns:mx="library://ns.adobe.com/flex/mx"
            implements="mx.controls.listClasses.IDropInListItemRenderer,mx.controls.listClasses.IListItemRenderer"
            horizontalScrollPolicy="off" width="100%">
    <fx:Script>
        <![CDATA[

            import mx.controls.listClasses.BaseListData;
            import mx.controls.listClasses.IDropInListItemRenderer;
            import mx.controls.listClasses.IListItemRenderer;
            import mx.events.ResizeEvent;


            private var _listData:BaseListData;
            private var _data:Object;

            private var _listOrData_c:Boolean = false;

            public function get listData():BaseListData
            {
                return _listData;
            }
            public function set listData(value:BaseListData):void
            {
                _listData = value;
                _listOrData_c = true;
                invalidateProperties();
            }

            public function get data():Object
            {
                return _data
            }
            public function set data(value:Object):void
            {
                _data = value;
                _listOrData_c = true;
                invalidateProperties();
            }

            override protected function commitProperties():void
            {
                if(_listOrData_c)
                {
                    _listOrData_c = false;
                    label.text = _listData.label;
                }

                super.commitProperties();
            }

        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- Place non-visual elements (e.g., services, value objects) here -->
    </fx:Declarations>
    <s:Group width="100%">
        <s:layout>
            <s:BasicLayout clipAndEnableScrolling="true" />
        </s:layout>
        <s:Label id="label" width="100%"/>
    </s:Group>
</s:Scroller>

Throw it into a AdvancedDataGrid and set some data with very large text blocks. Resize columns, then resize the grid itself, hopefully you can reproduce the same results. Make sure you set a max height on the item renderers like:

            <mx:AdvancedDataGridColumn id="adgc1" headerText="Name" dataField="label">
                <mx:itemRenderer>
                    <fx:Component>
                        <newLayouts:ScrollingTextItemRenderer maxHeight="60" />
                    </fx:Component>
                </mx:itemRenderer>
            </mx:AdvancedDataGridColumn>

Using Flex 4.1.

Thanks for the help.

Here are screenshots detailing the item renderer as it should function (as I have fixed the measuring to forcibly validate the label at the explicit current width before measuring):

Very wide column, no scroll bars, the labels measured height is shown in the row height enter image description here

Smaller width column, some renderers have hit max height and are creating scroll bars, the last renderer is still using the measured height of the label enter image description here

Smaller still column, all max heights are hit and scrollers are present for all labels, scrollers will select the row when used but allow scrolling so all text is viewable. enter image description here


Solution

  • After much closer inspection this morning, the meausre method for the DataGroup renderers themselves was not correclty validating the size of its children upon first measure pass.

    I need the labels in those items to have a restricted width so they will wordwrap appropriately, so when I am measuring the DataGroup row I need to set the width of each of its children and then measure the child. The problem was validateSize() was not correctly validating the elements size (the label was not being updated and generating its new text lines at this point). All subsequent measure passes already had a width validated to each child so measuring them again was correct. So when resizing the grid, the subsequent measure calls worked.

    I took to forcibly validating each child within the DataGroup's measure method and the correct heights are now being returned and as such the AdvancedDataGrid is acutally sizing its rows correclty now.

    This can be rather inefficient as each item is validated twice per lifecycle pass now, but the grid is performing as desired.

    Probably something similar going on with the ScrollingLabelItemRenderer as the label probably doesn't get its width validated when it measures itself the first time thus sets the wrong measured size which the grid accepts and uses as row height.

    I have the ScrollingLabelItemRenderer functioning correctly now again, I had to forcibly apply a width to the label and validate it when measuring the renderer becuase it was still using its previous width and text lines when measuring before applying a new width in the subsequent updateDisplayList ...

            override protected function measure():void
            {
                label.width = getExplicitOrMeasuredWidth() - verticalScrollBar.getExplicitOrMeasuredWidth();
                label.validateNow();
                super.measure();
            }