theflashbum / fcss

Flash Cascading StyleSheet Library
fcss.flashartofwar.com
83 stars 13 forks source link

Binding IStyle in a Spark Skin #12

Open robertburke opened 14 years ago

robertburke commented 14 years ago

I am trying to combine FCSS with Spark Skins - idea from here: http://seanhess.net/posts/flex_skins_and_styles. I want to use FCSS instead of Flex CSS.

The idea is the host component exposes a style property, which returns an IStyle cast as an Object, since you cannot bind to dynamic properties on an interface:

    private var _style:IStyle;

    [Bindable] 
    public function get style():Object
    {
        return _style;
    }

    public function set style(value:Object):void
    {
        _style = value as IStyle;
    }

Next, in the spark skin class, you could code something like this:

<mx:Image
    id="icon"
    color.disabled="{hostComponent.style.colorDisabled}"
    color.down="{hostComponent.style.colorDown}"
    color.up="{hostComponent.style.colorUp}"
    color.over="{hostComponent.style.colorOver}"/>

Two problems I encountered:

1) The binding does not work because Style is not an EventDispatcher. IStyle should extend IEventDispatcher, and Stye or AbstractOrderedObject should implement IEventDispatcher, and raise a PropertyChangeEvent when a property changes.

2) In my CSS, I would prefer to create style properties with dashes, e.g., "color-up". However, I cannot refer to the dynamic property on Style, except by using brackets (style['color-up']) which are not allowed in binding expressions. It would be great if FCSS converted "color-up" in my CSS to a "colorUp" property on the Style, which is pretty much how Flex CSS and HTML CSS work (e.g., "font-family" in CSS and "fontFamily" in JS or AS). Then I could say use style.colorUp in a binding expression.

Spark skinning appears to be the immediate future of Flex programming, but I want to be able to style my skins, and I think I could use FCSS to accomplish this if the above changes were made. Maybe this is not what FCSS was intended for, but I think it could work.

Glidias commented 14 years ago

The above example won't work because the IStyle Proxy implemenetation in F*CSS is only meant for storing and reflecting string values. Last time I checked, it even throws an error if the value you assigned to a IStyle object isn't string-based. The purpose of IStyle is to hold plain string values meant to be converted by a TypeHelperUtil, where reflection is done on a target component (through the PropertyMapUtil) to serialize the string value to be applied directly to the target component (just in time). This two-fold process is done by the Applicator class, and is a great way to allow property data-application for pure non meta-tag-supported Flash projects. I doubt the FCSS framework is going to use any of mx package/meta-tag dependencies for it's core classes, since it'll divert from it's main purpose as a pure Flash CSS solution. The AbstractOrderedObject is merely a property selector of string values, and not a VO host of bindable properties like what you're describing here. You'd probably get an error in the above example since the target color value is uint (i assume) and not a string.

If you need to have the binding functionality above, you need to create a style wrapper object that does part of the above two-fold process within the context of a host component or class. (I assume you know how to create a Proxy class with the Bindable meta tag on top). In fact, I have an outline for such a class, which requires the following dependencies: 1) The host component ( or class). 2) The style object (IStyle). Declare this as a plain Object to allow setting/getting properties from it and for better cross-platform interaction. 3) A typehelper implementation. (You can simply use the static F_CSS TypeHelperUtil for this) since F_CSS does not support an interface for this. 4) A property map cache implementation to perform introspection on the host component/class in order to retrieve it's property map. (You can simply use the static F_CSS PropertyMapUtil for this) since F_CSS does not support an interface for this.

Getter: In the @getProperty(name):@ method of your proxy wrapper class, you simply use something like @return hostPropertyMap[name] ? TypeHelperUtil.getType( styleObj[name] : hostPropertyMap[name]) : styleObj[name];@; For added performance, you can even cache the requested value, so you don't have to perform type-conversion everytime the value is re-requested from other requesters.

Setters: 1) setProperty(name, val) :: can be used to directly set string-only values on the IStyle object, which could dispatch a change event for that particular property. TypeConversion can be done immediately if there's a host property map available, and saved into the result cache. Otherwise, you'd have to clear the property in the result cache (if found) and perform type-conversion on the next request. 2) public set hostComponent(target:Object) setter re-sets the host component and saves out a new property map for the new host through PropertyMapUtil. propertyMap(target). 3) public set styleObj(val:Object) setter allows switching between IStyle objects. I prefer to declare this as a plain Object since the IStyle interface's methods are F*CSS management specific and isn't needed in this case. In fact, supplying a plain native Flash Object should suffice as far as the proxy wrapper class is concerned. All setters should dispatch PropertyChangeEvents to trigger updates on listening components. This allows you to switch to different IStyles for the host component/class and thus trigger skin changes on the rest of the application. If you have cached converted values,remember to reset the cache whenever either the core host or core IStyle object reference changes.