10 Replies Latest reply on Sep 1, 2009 7:34 AM by ChivertonT

    Degrafa vs. FXG (and Spark) [Bindable]

    viatropos Level 1

      I've noticed that FXG, and Spark in general, has very few [Bindable] properties, while in Degrafa, almost every property is [Bindable], some of the classes event have class [Bindable] tags.  I am taking advantage of this greatly.

       

      Are you guys planning on making more of the properties [Bindable]?  Or does the compiler auto-generate custom [Bindable] events in the background (that would be very nice)?

       

      A reasonable compromise would be to have each property dispatch a custom "myNameChange" event, only if "target.hasEventListener('myNameChange')".  Otherwise this forces us into a position where, to bind to the properties, we have to extend every class and add that functionality.

       

      For instance, I would like to know when the "layout" changed on a skinnable container, and when "clipAndEnableScrolling" changes, but they're not [Bindable] like most of the other properties in there.

       

      To prevent a performance hit, you could just do something like Degrafa does, with custom events:

       

      [Bindable(event="myPropertyChange")]

      public function get myProperty():String

      {

           return _myProperty

      }

      public function set myProperty(value:String):void

      {

           if (_myProperty != value)

           {

                var oldValue:String = _myProperty;

                _myProperty = value;

                dispatchPropertyChangeEvent("myProperty", "myPropertyChange", oldValue, value);

           }

      }

       

      protected function dispatchPropertyChangeEvent(property:String, eventType:String, oldValue:*, newValue:*):void {

           if (hasEventListener(eventType))

                dispatchEvent(new Event(eventType)) // or PropertyChangeEvent....

      }

       

      //////////

       

      If Flex did this in the background for properties not marked [Bindable], that would be EXTREMELY helpful, and I don't think it would change/break anything.  I feel like this is already the case...

       

      Let me know what you think.

       

      Lance

        • 1. Re: Degrafa vs. FXG (and Spark) [Bindable]
          Ely Greenfield Level 1

          How are you taking advantage of the bindable properties in Degrafa?

           

          Our general policy in Spark and MXML Graphics is that only properties that can be modified by the user, or by complex computations performed by the framework (i.e., width/height), should be bindable. Other properties that are only modified by the developer can be bottlenecked by the developer, and shouldn't incur the overhead of bindability.

           

          E.

          • 2. Re: Degrafa vs. FXG (and Spark) [Bindable]
            viatropos Level 1

            Hey Ely,

             

             

            The main example is in creating controllers that are attached to the Skins with Degrafa objects in them (like OpenFlux does it).  The Controllers use BindingUtils.bindProperty to listen for when a Fill.gradientType changes, or when the Polygon.data changes, and then it updates another thing.  That's the most generic part, but there's lots of that.  Like creating a shadow based on the gradient angle and the position of the object.

             

            Another example is in restricting a button's label width/height to the (rectangle width - the corner radii sizes).  And those corner radii change with the state.  I don't do that in the skin, I do that in a ButtonLabelController, which I can add to any skin and reuse the code. But it requires binding.

             

            Or tilting the panel and changing the drop shadow size when the verticalScrollPosition, or any of the scrolling related variables change.

             

            Or changing the color as a function of the gradient fill angle in a skin to easily simulate simple lighting.

             

            For the horizontalScrollPosition/verticalScrollPosition, you can create an animated scroll bar very easily, and more fully featured than the built in stuff in Spark, with a controller that binds to those properties on a Group or Layout.

             

            Granted you can do all this without binding, but binding just makes it soooo much easier.

             

            Plus there shouldn't be much overhead if we're not dispatching events if it doesn't have an event listener for it, and they aren't generically "propertyChange" events.  That's what Degrafa does in some places.

             

            By not having the option to bind to it, I am restricted to a particular coding style, and I miss out on some helpful coding practices, like composition over inheritance.  Currently in Spark, I can't extract out "controller" logic from the skin (that does something like the above) into some other object, unless I know when they're updated.  Some other options I currently have using the Spark Architecture:

             

            1) Write some enterFrameHandler that updated properties based on other property changes.  Would require some dictionary keeping track of old property values on a target.

            2) Extend the skin class and add [Bindable] tags, or extend the Group and add them.

            3) Extend the Skin or component, and do a bunch of logic in the invalidation methods, which isn't necessary, especially during animations.  Plus I can't reuse that logic in another component without copy-pasting, and that's just too much work.  Like if I wanted to have an editable TextInput and an editable TextInput, I'd have to extend both with the same code in each.  I could solve that with a Controller no problem.

             

             

            I think the controller architecture makes things so much easier to do, and classes so much easier to customize, without code duplication and inheritance.  But that's another point.

             

            Binding doesn't need to be "active" if nothing's bound to it, and we can have an option to prevent binding on those properties with a variable like degrafa has: "enableEvents" or "suppressEventProcessing". That shouldn't impact performance.

             

            Lance

            • 3. Re: Degrafa vs. FXG (and Spark) [Bindable]
              viatropos Level 1

              Here's some stats using Grant Skinner's PerformanceTest class:

               

              ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

              performance.BindablePerformance (10,000 iterations)

              Tests [Bindable] performance in Flex                                   

              ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

              method...............................................................ttl ms...avg ms

              A_DefaultBinding                                                1167     0.12

              A_DefaultBinding_Again                                      1299     0.13

              B_CustomBindingEvent                                       1249     0.12

              B_CustomBindingEvent_Again                             1285     0.13

              C_CustomBindingEventWithCondition                   1215     0.12

              C_CustomBindingEventWithCondition_Again         1199     0.12

              D_NoBinding                                                       1193     0.12

              D_NoBinding_Again                                             1203     0.12

              The attached class shows how they were implemented.

              • 4. Re: Degrafa vs. FXG (and Spark) [Bindable]
                viatropos Level 1

                Here's some stats using Grant Skinner's PerformanceTest class:

                 

                 

                ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

                performance.BindablePerformance (10,000 iterations)

                Tests [Bindable] performance in Flex                                 

                ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

                method...............................................................ttl ms...avg ms

                A_DefaultBinding                                                1167     0.12

                A_DefaultBinding_Again                                      1299     0.13

                B_CustomBindingEvent                                       1249     0.12

                B_CustomBindingEvent_Again                             1285     0.13

                C_CustomBindingEventWithCondition                   1215     0.12

                C_CustomBindingEventWithCondition_Again         1199     0.12

                D_NoBinding                                                       1193     0.12

                D_NoBinding_Again                                             1203     0.12

                 

                The attached class shows how they were implemented.
                • 5. Re: Degrafa vs. FXG (and Spark) [Bindable]
                  viatropos Level 1

                  Sorry, that one was kind of deceiving... each property was a UIComponent and I was creating a new UIComponent each iteration, so it averaged out about the same.  If I change each property to a Number and just increment it, it looks like this:

                   

                   

                  ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

                  performance.BindablePerformance (10,000 iterations)

                  Tests [Bindable] performance in Flex                         

                  ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

                  method...............................................................ttl ms...avg ms

                  A_DefaultBinding                                                 118      11.80

                  A_DefaultBinding_Again                                       119      11.90

                  B_CustomBindingEvent                                        87       8.70

                  B_CustomBindingEvent_Again                              91       9.10

                  C_CustomBindingEventWithCondition                    23       2.30

                  C_CustomBindingEventWithCondition_Again          20       2.00

                  D_NoBinding                                                        11       1.10

                  D_NoBinding_Again                                              12       1.20

                   

                  ... SECOND ROUND:

                   

                  A_DefaultBinding                                                 134      13.40

                  A_DefaultBinding_Again                                       122      12.20

                  B_CustomBindingEvent                                        83       8.30

                  B_CustomBindingEvent_Again                              78       7.80

                  C_CustomBindingEventWithCondition                    23       2.30

                  C_CustomBindingEventWithCondition_Again          26       2.60

                  D_NoBinding                                                        12       1.20

                  D_NoBinding_Again                                              12       1.20

                   

                   

                  ... So it looks like just adding that conditional statement to check for the event listener is kind of expensive.  But it's only a 2x performance hit instead of ~7-8x for dispatching an unnecessary event (like setting alpha in the UIComponent when nothing is bound to it), and the default binding, which is 10-11x more expensive!

                   

                  1x:        No binding

                  2x:        Custom binding event, not dispatched (because there's no event listener)

                  7-8x:     Custom binding event, dispatched (by default by Flex)

                  10-11x:  Default binding event, dispatched (by default by Flex)

                   

                  This might be a factor in why animating UIComponents is sooo much slower/choppier than animating Sprites or whatnot, because alpha, x, y, and whatever else dispatch events when there's nothing bound to them.

                   

                  > grep -r "\"xChanged\"" ./*

                  > ./framework/src/mx/containers/utilityClasses/ConstraintColumn.as: [Bindable("xChanged")]

                  > ./framework/src/mx/containers/utilityClasses/ConstraintColumn.as: dispatchEvent(new Event("xChanged"));

                  > ./framework/src/mx/core/UIComponent.as: [Bindable("xChanged")]

                  > ./framework/src/mx/core/UIComponent.as: dispatchEvent(new Event("xChanged"));

                  > ./framework/src/mx/core/UIComponent.as: dispatchEvent(new Event("xChanged"));

                   

                  There is nothing in the framework listening/bound to "xChanged", or most of the other properties dispatching events.

                   

                  That "set x" accessor shouldn't be dispatching an event every time its set, neither should y, width, height, alpha, explicitWidth/height...

                   

                  override public function set x(value:Number):void

                  {

                       if (x == value)

                            return;

                       if (_layoutFeatures == null)

                       {

                            super.x = value;

                       }

                       else

                       {

                            _layoutFeatures.layoutX = value;

                            invalidateTransform();

                       }

                       invalidateProperties();

                       dispatchEvent(new Event("xChanged"));

                  }

                   

                  ...should become

                   

                  override public function set x(value:Number):void

                  {

                       if (x == value)

                            return;

                       if (_layoutFeatures == null)

                       {

                            super.x = value;

                       }

                       else

                       {

                            _layoutFeatures.layoutX = value;

                            invalidateTransform();

                       }

                       invalidateProperties();

                   

                       if (hasEventListener("xChanged"))

                            dispatchEvent(new Event("xChanged"));

                  }

                   

                  ...That should help out in animations, and just make performance better in general.

                   

                  Best,

                  Lance

                  • 6. Re: Degrafa vs. FXG (and Spark) [Bindable]
                    viatropos Level 1

                    I'm going to try to integrate this into the framework.  It would only be one extra step to "suspendEventProcessing" during animations if you wanted.

                     

                    If only it was easier to set up the sdk development environment

                    • 8. Re: Degrafa vs. FXG (and Spark) [Bindable]
                      Daniel Rinehart Level 1

                      The avg ms figures in your last post seem off. If the test was run for 10,000 iterations the avg ms should be 0.0118 for A_DefaultBinding etc. The relative differences in the methods stays the same. Although I'd suspect something else is contributing the overall choppiness given how little even the most expensive call adds.

                      • 9. Re: Degrafa vs. FXG (and Spark) [Bindable]
                        viatropos Level 1

                        Should have posted my new test, sorry bout that.

                         

                        10 iterations, where each method runs 1000 property settings.  So it wasn't in the fraction of a fraction of a ms...