views:

395

answers:

2

Problem solved, see below

Question

I'm working in Flex Builder 3 and I have two ActionScript 3 classes (ABC and XYZ) and a Flex MXML project (main.mxml). I have an instance of XYZ as a property of ABC, and I want XYZ's properties to be visible ([Bindable]) in the Flex project in text controls.

Unfortunately, only prop3 and prop4 update when they are changed. I've entered the debugger to make sure that prop1 and prop2 change, but they are not being updated in the text controls.

Here's the code:

ABC.as

[Bindable]
public class ABC extends UIComponent {
    /* Other properties */

    public var xyz:XYZ = new XYZ();

    /* Methods that update xyz */
}

XYZ.as

[Bindable]
public class XYZ extends Object {
     private var _prop1:uint = 0;
     private var _prop2:uint = 0;
     private var _prop3:uint = 0;
     private var _prop4:uint = 1;

     public function get prop1():uint {
         return _prop1;
     }

     public function set prop1(value:uint):void {
         _prop1 = value;
     }

     /* getters and setters for prop2, prop3, and prop4 */
}

main.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:com="com.*" />
    <com:ABC id="abc" />
    <mx:Text text="{abc.xyz.prop1}" />
    <mx:Text text="{abc.xyz.prop2}" />
    <mx:Text text="{abc.xyz.prop3}" />
    <mx:Text text="{abc.xyz.prop4}" />
</mx:Application>

Answer

It's not apparent from the small code snippets that I posted, but from within XYZ I was updating _prop3 and _prop4 using their setters. In constrast, I updated _prop1 and _prop2 through their private variables, not their setters. Thus, properties 1 and 2 were not dispatching update events.

+3  A: 

It looks like your getters are returning voids. They should be returning uints, according to your field types.

Otherwise your code should be working fine. I've assembled and tested a working version with a Timer that sets all four values, so you can see all four updating:

Main.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:local="*" creationComplete="onCreationComplete()">

    <mx:Script>
     <![CDATA[

      private function onCreationComplete():void
      {
       var t:Timer = new Timer(1000);
       t.addEventListener(TimerEvent.TIMER, t_tick);
       t.start();
      }

      private function t_tick(event:TimerEvent):void
      {
       var i:uint = Timer(event.currentTarget).currentCount;

       abc.xyz.prop1 = i;
       abc.xyz.prop2 = i;
       abc.xyz.prop3 = i;
       abc.xyz.prop4 = i;
      }

     ]]>
    </mx:Script>

    <local:ABC id="abc" />

    <mx:VBox>
     <mx:Text text="{abc.xyz.prop1}" />
     <mx:Text text="{abc.xyz.prop2}" />
     <mx:Text text="{abc.xyz.prop3}" />
     <mx:Text text="{abc.xyz.prop4}" />
    </mx:VBox>

</mx:Application>

ABC.as

package
{
    import mx.core.UIComponent;

    [Bindable]
    public class ABC extends UIComponent
    {
     public var xyz:XYZ = new XYZ();

     public function ABC()
     {
      super();
     }
    }
}

XYZ.as

package
{
    [Bindable]
    public class XYZ extends Object
    {
     private var _prop1:uint = 0;
     private var _prop2:uint = 0;
     private var _prop3:uint = 0;
     private var _prop4:uint = 1;

     public function XYZ()
     {
      super();
     }

     public function get prop1():uint {
      return _prop1;
     }

     public function set prop1(value:uint):void {
      _prop1 = value;
     }

     public function get prop2():uint {
      return _prop2;
     }

     public function set prop2(value:uint):void {
      _prop2 = value;
     }

     public function get prop3():uint {
      return _prop3;
     }

     public function set prop3(value:uint):void {
      _prop3 = value;
     }

     public function get prop4():uint {
      return _prop4;
     }

     public function set prop4(value:uint):void {
      _prop4 = value;
     }
    }
}

Have a look at those, plug things in and you should see it all come together. Post back if you have any questions. Cheers.

Christian Nunciato
Actually, it turns out I only made the void return type mistake here. All of the setters in my actual code return uint. Sorry for the confusion.
Andrew Keeton
Ok. Then the code I've posted here ought to work for you -- I've tested it to be sure. Feel free to give it a run and compare it to what you've got now, and use whichever pieces you need to fix things on your end. Good luck!
Christian Nunciato
Sorry it's been so long but I've been away from the code for a little bit. I just tried your test example and it worked, so I guess I have a bug elsewhere in my code. Thanks!
Andrew Keeton
Aha I fixed it. It turns out when I changed properties 3 and 4 (from within XYZ) I was using the properties' setters, thus triggering the proper events to be dispatched. With properties 1 and 2, I was changing them by modifying _prop1 and _prop2. Since I wasn't calling the setters, no events were dispatched. I guess I learned something today :)
Andrew Keeton
Excellent! Glad it helped. Cheers. :)
Christian Nunciato
hey gud answer :)
Rahul Garg
+1  A: 

When you define your bindable sources through the use of getters and setters, the bindings don't seem to work. The solution is to declare a bindable event for your getter and dispatch the event in your setter:

[Bindable]
public class XYZ extends Object {
     private var _prop1:uint = 0;
     private var _prop2:uint = 0;
     private var _prop3:uint = 0;
     private var _prop4:uint = 1;

     [Bindable(event="prop1Changed")]
     public function get prop1():uint {
         return _prop1;
     }

     public function set prop1(value:uint):void {
         _prop1 = value;
         dispatchEvent (new Event ("prop1Changed"));
     }

     /* getters and setters for prop2, prop3, and prop4 */
}

So whenever your private member changes, an event is dispatched that notifies any component linked to the getter that the property has changed.

Mircea Grelus
This isn't necessary if the class is marked [Bindable]. Also requires specific listeners be set up for each property -- it's fine as an illustration, but what the OP's asked is out-of-the-box stuff that should "just work" without all the extra goo.
Christian Nunciato
You are right. If the class is marked as bindable there is no need to explicitly mark the properties also.
Mircea Grelus