tags:

views:

5186

answers:

4

I'm using the AdvancedDataGrid widget and I want two columns to be radio buttons, where each column is it's own RadioButtonGroup. I thought I had all the necessary mxxml, but I'm running into a strange behavior issue. When I scroll up and down, the button change values! The selected button becomes deselected, and unselected ones become selected. Anyone have a clue about this bug? Should I being going about this a different way. -- Here's a stripped down example of what I trying to do.

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
  <mx:RadioButtonGroup id="leftAxisGrp" />
  <mx:RadioButtonGroup id="rightAxisGrp">
    <mx:change>
      <![CDATA[
        trace (rightAxisGrp.selection);
        trace (rightAxisGrp.selection.data.name);
      ]]>
    </mx:change>
  </mx:RadioButtonGroup>
  <mx:AdvancedDataGrid
      id="readingsGrid"
      designViewDataType="flat"
      height="150" width="400"
      sortExpertMode="true"
      selectable="false">
    <mx:columns>
      <mx:AdvancedDataGridColumn
          headerText="L" width="25" paddingLeft="6"
          dataField="left" sortable="false">
        <mx:itemRenderer>
          <mx:Component>
            <mx:RadioButton groupName="leftAxisGrp" />
          </mx:Component>
        </mx:itemRenderer>
      </mx:AdvancedDataGridColumn>
      <mx:AdvancedDataGridColumn
          headerText="R" width="25" paddingLeft="6"
          dataField="right" sortable="false">
        <mx:itemRenderer>
          <mx:Component>
            <mx:RadioButton groupName="rightAxisGrp" />
          </mx:Component>
        </mx:itemRenderer>
      </mx:AdvancedDataGridColumn>
      <mx:AdvancedDataGridColumn headerText="" dataField="name" />
    </mx:columns>
    <mx:dataProvider>
      <mx:Array>
        <mx:Object left="false" right="false" name="Reddish-gray Mouse Lemur" />
        <mx:Object left="false" right="false" name="Golden-brown Mouse Lemur" />
        <mx:Object left="false" right="false" name="Northern Rufous Mouse Lemur" />
        <mx:Object left="false" right="false" name="Sambirano Mouse Lemur" />
        <mx:Object left="false" right="false" name="Simmons' Mouse Lemur" />
        <mx:Object left="false" right="false" name="Pygmy Mouse Lemur" />
        <mx:Object left="false" right="false" name="Brown Mouse Lemur" />
        <mx:Object left="false" right="false" name="Madame Berthe's Mouse Lemur" />
        <mx:Object left="false" right="false" name="Goodman's Mouse Lemur" />
        <mx:Object left="false" right="false" name="Jolly's Mouse Lemur" />
        <mx:Object left="false" right="false" name="Mittermeier's Mouse Lemur" />
        <mx:Object left="false" right="false" name="Claire's Mouse Lemur" />
        <mx:Object left="false" right="false" name="Danfoss' Mouse Lemur" />
        <mx:Object left="false" right="false" name="Lokobe Mouse Lemur" />
        <mx:Object left="true" right="true" name="Bongolava Mouse Lemur" />
      </mx:Array>
    </mx:dataProvider>
  </mx:AdvancedDataGrid>
</mx:WindowedApplication>


UPDATED (thanks bill!)

Alright! Go it working. I just had to make a couple of changes from bill's suggestion. Mainly using ArrayCollection with ObjectProxy so it was both bindable and dynamic. One weird thing - I couldn't select a button in the first row if I filled in the array at construction time; I had to delay that until the creationComplete event was fired (which is fine, since I'm going to populate the grid from a db anyway).

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
  <mx:Script>
    <![CDATA[
      import mx.utils.ObjectProxy;
      import mx.collections.ArrayCollection;

      [Bindable]
      private var myData:ArrayCollection = new ArrayCollection ();

      private function selectItem (selObject:Object, property:String) : void
      {
        for each (var obj:ObjectProxy in myData) {
          obj[property] = (obj.name === selObject.name);
        }
        readingsGrid.invalidateDisplayList ();
      }
    ]]>
  </mx:Script>
  <mx:RadioButtonGroup id="leftAxisGrp">
    <mx:change>
      <![CDATA[
        selectItem (leftAxisGrp.selectedValue, 'left');
      ]]>
    </mx:change>
  </mx:RadioButtonGroup>
  <mx:RadioButtonGroup id="rightAxisGrp">
    <mx:change>
      <![CDATA[
        selectItem (rightAxisGrp.selectedValue, 'right');
      ]]>
    </mx:change>
  </mx:RadioButtonGroup>
  <mx:AdvancedDataGrid
      id="readingsGrid"
      designViewDataType="flat"
      dataProvider="{myData}"
      sortExpertMode="true"
      height="150" width="400"
      selectable="false">
    <mx:columns>
      <mx:AdvancedDataGridColumn id="leftCol"
          headerText="L" width="25" paddingLeft="6" sortable="false">
        <mx:itemRenderer>
          <mx:Component>
            <mx:RadioButton groupName="leftAxisGrp"
                buttonMode="true" value="{data}" selected="{data.left}" />
          </mx:Component>
        </mx:itemRenderer>
      </mx:AdvancedDataGridColumn>
      <mx:AdvancedDataGridColumn id="rightCol"
          headerText="R" width="25" paddingLeft="6" sortable="false">
        <mx:itemRenderer>
          <mx:Component>
            <mx:RadioButton groupName="rightAxisGrp"
                buttonMode="true" value="{data}" selected="{data.right}" />
          </mx:Component>
        </mx:itemRenderer>
      </mx:AdvancedDataGridColumn>
      <mx:AdvancedDataGridColumn headerText="" dataField="name" />
    </mx:columns>
    <mx:creationComplete>
      <![CDATA[
      myData.addItem(new ObjectProxy ({ left:true, right:true, name:"Golden-brown Mouse Lemur" }));
      myData.addItem(new ObjectProxy ({ left:false, right:false, name:"Reddish-gray Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Northern Rufous Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Sambirano Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Simmons' Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Pygmy Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Brown Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Madame Berthe's Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Goodman's Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Jolly's Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Mittermeier's Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Claire's Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Danfoss' Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Lokobe Mouse Lemur" }));
      myData.addItem(   new ObjectProxy ({ left:false, right:false, name:"Bongolava Mouse Lemur" }));    
      ]]>
    </mx:creationComplete>
  </mx:AdvancedDataGrid>
</mx:WindowedApplication>
A: 

Reproduced this. Likely to be a ADG bug, we've run into a few here. (Didn't find this one on bugs.adobe.com, but their search sucks).

You could try Flex 3.0.3, or a nightly build here (warning, may be pretty broken), and see if they've fixed it, or you could try implementing a custom renderer, but that is a pain to get right.

Simon Buchan
+1  A: 

What's happening here is that Flex only creates itemRenderer instances for the visible columns. When you scroll around, those instances get recycled. So if you scroll down, the RadioButton object that was drawing the first column of the first row may now have changed to instead be drawing the first column of the seventh row. Flex resets the "data" property of the itemRenderer whenever this happens.

So while there are 15 rows of data, there are only ever 12 RadioButtons (6 for the "left", and 6 for the "right" for the 6 visible rows), not 30 RadioButtons, as you might expect. This isn't a big problem if you're only displaying the selection, but it becomes more of a problem when you allow updates.

To fix the display issue, instead of setting the "dataField" on the column, you can bind the RadioButton's "selected" property to the itemRenderer's data.left (or right) value. You'll then need to make the items in your dataProvider "Bindable".

To fix the update issue, since you'd be binding directly to the dataProvider item values, you need to be sure to update them. Since there's isn't one RadioButton per-item, you'll need another scheme for that. In this case I put in a handler that goes and sets the left/right property of each item to "false", except for the "selected" one, which gets set to "true".

I updated your example code based on these thoughts. Try something like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application  layout="absolute"
    xmlns:my="*"
    xmlns:mx="http://www.adobe.com/2006/mxml"&gt;
  <mx:RadioButtonGroup id="leftAxisGrp"
       change="selectItem(leftAxisGrp.selectedValue, 'left');"/>
  <mx:RadioButtonGroup id="rightAxisGrp"
       change="selectItem(rightAxisGrp.selectedValue, 'right');">
  </mx:RadioButtonGroup>
  <mx:AdvancedDataGrid
      id="readingsGrid"
      designViewDataType="flat"
      height="150" width="400"
      sortExpertMode="true"
      selectable="false"
      dataProvider="{adgData.object}">
    <mx:columns>
      <mx:AdvancedDataGridColumn
          headerText="L" width="25" paddingLeft="6"
          sortable="false">
        <mx:itemRenderer>
          <mx:Component>
            <mx:RadioButton groupName="leftAxisGrp" 
                value="{data}" selected="{data.left}"/>
          </mx:Component>
        </mx:itemRenderer>
      </mx:AdvancedDataGridColumn>
      <mx:AdvancedDataGridColumn
          headerText="R" width="25" paddingLeft="6"
          sortable="false">
        <mx:itemRenderer>
          <mx:Component>
            <mx:RadioButton groupName="rightAxisGrp"
                value="{data}" selected="{data.right}"/>
          </mx:Component>
        </mx:itemRenderer>
      </mx:AdvancedDataGridColumn>
      <mx:AdvancedDataGridColumn headerText="" dataField="name" />
    </mx:columns>
  </mx:AdvancedDataGrid>
  <mx:Model id="adgData">
      <root>
        <object left="false" right="false" name="Reddish-gray Mouse Lemur" />
        <object left="false" right="false" name="Golden-brown Mouse Lemur" />
        <object left="false" right="false" name="Northern Rufous Mouse Lemur" />
        <object left="false" right="false" name="Sambirano Mouse Lemur" />
        <object left="false" right="false" name="Simmons' Mouse Lemur" />
        <object left="false" right="false" name="Pygmy Mouse Lemur" />
        <object left="false" right="false" name="Brown Mouse Lemur" />
        <object left="false" right="false" name="Madame Berthe's Mouse Lemur" />
        <object left="false" right="false" name="Goodman's Mouse Lemur" />
        <object left="false" right="false" name="Jolly's Mouse Lemur" />
        <object left="false" right="false" name="Mittermeier's Mouse Lemur" />
        <object left="false" right="false" name="Claire's Mouse Lemur" />
        <object left="false" right="false" name="Danfoss' Mouse Lemur" />
        <object left="false" right="false" name="Lokobe Mouse Lemur" />
        <object left="true" right="true" name="Bongolava Mouse Lemur" />
      </root>
  </mx:Model>
  <mx:Script>
    <![CDATA[
     private function selectItem(selObject:Object, property:String) : void {
      for each(var obj:Object in adgData.object) {
       obj[property] = (obj === selObject);
      }
      readingsGrid.invalidateDisplayList();
     }
    ]]>
  </mx:Script>
</mx:Application>
bill d
A: 

One weird thing - I couldn't select a button in the first row if I filled in the array at construction time; I had to delay that until the creationComplete event was fired

I'm running into a similar issue. Can you please elaborate a bit on the solution, like what you attached the creationComplete event to? Thanks.

In the second code block, there's a <creationComplete> tag at the bottom. It's attached to the AdvancedDataGrid.
eduffy
A: 

hi -- I have a similar issue with an XML dataprovider and a checkbox itemrenderer -- any help with applying bill's logic to that scenario?

effectively i have an attribute on each element (row) which should set and be set by the associated checkbox...

thanks!

Darrell Berry