5 Replies Latest reply on May 31, 2011 1:54 AM by Sébastien VARLET

    Custom style property in a custom component

    Sébastien VARLET Level 1

      Hi,

       

      I'm trying to create a custom container and its default skin. What I would like to do is something like a border container with a title placed on the left above the top border.

       

      I don't know if it matters but I'm creating these in a specific Library, not in the (air) project using it.

       

      Here is my code:

       

      LabelledGroupSkin

      <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" 
               xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled="0.5">
          <fx:Metadata>[HostComponent("com.svarlet.newSkins.labelledGroup.LabelledGroup")]</fx:Metadata>
      
          <fx:Script fb:purpose="styling">
              <![CDATA[         
                     public static const DEFAULT_BG_COLOR:uint = 0xFFFFFF;
                     
                  /**
                   *  @private
                   */
                  override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
                  {
                          if (isNaN(hostComponent.getStyle("borderWeight1"))) {
                               stroke.weight = 1;
                          } else {
                               stroke.weight = hostComponent.getStyle("borderWeight1");
                               stroke.color = hostComponent.getStyle("borderColor1");
                          }
                          
                      if (isNaN(getStyle("backgroundColor")))
                      {
                               bgFill.color = DEFAULT_BG_COLOR;
                          bgFill.alpha = 0;
                      }
                      else
                      {
                          bgFill.color = getStyle("backgroundColor");
                          bgFill.alpha = getStyle("backgroundAlpha");
                      }
                          labelDisplay.setStyle("backgroundColor", bgFill.color);
                          contentGroupLayout.paddingTop = uint(labelDisplay.getStyle("fontSize"))/2;
      
                      super.updateDisplayList(unscaledWidth, unscaledHeight);
                  }
              ]]>        
          </fx:Script>
          
          <s:states>
              <s:State name="normal" />
              <s:State name="disabled" />
          </s:states>
           
          <!--- Defines the appearance of the SkinnableContainer class's background. -->
          <s:Rect id="background" left="0" right="0" top="0" bottom="0">
              <s:fill>
                  <!--- @private -->
                  <s:SolidColor id="bgFill" color="{DEFAULT_BG_COLOR}"/>
              </s:fill>
                <s:stroke>
                     <s:SolidColorStroke id="stroke" joints="round" caps="round" />
                </s:stroke>
          </s:Rect>
          
          <!--
              Note: setting the minimum size to 0 here so that changes to the host component's
              size will not be thwarted by this skin part's minimum size.   This is a compromise,
              more about it here: http://bugs.adobe.com/jira/browse/SDK-21143
          -->
          <!--- @copy spark.components.SkinnableContainer#contentGroup -->
          <s:Group id="contentGroup"
                      left="{stroke.weight}" right="{stroke.weight}"
                      top="{stroke.weight}" bottom="{stroke.weight}"
                      minWidth="0" minHeight="0">
              <s:layout>
                  <s:VerticalLayout id="contentGroupLayout"/>
              </s:layout>
          </s:Group>
      
           
           <s:Label id="labelDisplay"
                      left="20" top="{-uint(labelDisplay.getStyle('fontSize'))/2}"
                      paddingLeft="3" paddingRight="3" />
      </s:Skin>
      
       
      

       

      LabelledGroup:

      <s:SkinnableContainer xmlns:fx="http://ns.adobe.com/mxml/2009" 
                 xmlns:s="library://ns.adobe.com/flex/spark"
                 xmlns:mx="library://ns.adobe.com/flex/mx"
                 skinClass="com.svarlet.newSkins.labelledGroup.LabelledGroupSkin">
           <fx:Script>
                <![CDATA[
                     import spark.components.Label;
                     
                     [SkinPart(required="true")]
                     public var labelDisplay:Label;
                     
                     private var _label:String;
                     
                     override protected function partAdded(partName:String, instance:Object):void
                     {
                          if (instance == labelDisplay) {
                               labelDisplay.text = label;
                          }
                     }
                     
                     [Bindable("labelChanged")]
                     public function get label():String
                     {
                          return _label;
                     }
                     
                     public function set label(value:String):void
                     {
                          _label = value;
                          if (labelDisplay)
                               labelDisplay.text = label;
                          dispatchEvent(new Event("labelChanged"));
                     }
                ]]>
           </fx:Script>
           
           <fx:Metadata>
                [Style(name="borderWeight1", type="uint", format="Length")]
                [Style(name="borderColor1", type="uint", format="Color")]
           </fx:Metadata>
      </s:SkinnableContainer>
      
       
      

       

      A component (TotoComponent) of my project based on the LabelledGroup component:

      <labelledGroup:LabelledGroup xmlns:fx="http://ns.adobe.com/mxml/2009" 
                                          xmlns:s="library://ns.adobe.com/flex/spark" 
                                          xmlns:mx="library://ns.adobe.com/flex/mx"
                                          xmlns:labelledGroup="com.svarlet.newSkins.labelledGroup.*"
                                          label="toto component !"
                                          width="400" height="200">
           <labelledGroup:layout>
                <s:VerticalLayout />
           </labelledGroup:layout>
           
           <s:Button label="test" />
           <s:List width="100%" height="100%" />
           <s:Button label="test2" />
      </labelledGroup:LabelledGroup>
      
       
      

       

      Now the problem...

      If I let the TotoComponent like this I have a 1px black border around the component. This was expected. Now If set the value of the borderColor1 and borderWeight1 style properties in my TotoComponent, I get a runtime error:

       

      Error: Required skin part labelDisplay cannot be found.
           at spark.components.supportClasses::SkinnableComponent/findSkinParts()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\supportClasses\SkinnableComponent.as:726]
           at spark.components.supportClasses::SkinnableComponent/attachSkin()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\supportClasses\SkinnableComponent.as:701]
           at spark.components.supportClasses::SkinnableComponent/validateSkinChange()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\supportClasses\SkinnableComponent.as:443]
           at spark.components.supportClasses::SkinnableComponent/createChildren()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\supportClasses\SkinnableComponent.as:406]
           at spark.components::SkinnableContainer/createChildren()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:879]
           at mx.core::UIComponent/initialize()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:7624]
           at com.svarlet.newSkins.labelledGroup::LabelledGroup/initialize()
           at com.svarlet.remindMe.presentation.common::Toto/initialize()
           at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:7485]
           at mx.core::UIComponent/addChildAt()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:7189]
           at spark.components::Group/addDisplayObjectToDisplayList()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:2037]
           at spark.components::Group/http://www.adobe.com/2006/flex/mx/internal::elementAdded()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:1628]
           at spark.components::Group/setMXMLContent()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:633]
           at spark.components::Group/createChildren()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:855]
           at mx.core::UIComponent/initialize()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:7624]
           at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:7485]
           at mx.core::UIComponent/addChildAt()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:7189]
           at spark.components::Group/addDisplayObjectToDisplayList()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:2037]
           at spark.components::Group/http://www.adobe.com/2006/flex/mx/internal::elementAdded()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:1628]
           at spark.components::Group/setMXMLContent()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:633]
           at spark.components::Group/set mxmlContent()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Group.as:573]
           at spark.components::SkinnableContainer/set mxmlContent()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:657]
           at spark.components::SkinnableContainer/createDeferredContent()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:1050]
           at spark.components::SkinnableContainer/createContentIfNeeded()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:1078]
           at spark.components::SkinnableContainer/createChildren()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\SkinnableContainer.as:885]
           at spark.components::Application/createChildren()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Application.as:1274]
           at mx.core::UIComponent/initialize()[E:\dev\hero_private\frameworks\projects\framework\src\mx\core\UIComponent.as:7624]
           at spark.components::Application/initialize()[E:\dev\hero_private\frameworks\projects\spark\src\spark\components\Application.as:1259]
           at spark.components::WindowedApplication/initialize()[E:\dev\hero_private\frameworks\projects\airspark\src\spark\components\WindowedApplication.as:1834]
           at RemindMe/initialize()
           at mx.managers.systemClasses::ChildManager/childAdded()[E:\dev\hero_private\frameworks\projects\framework\src\mx\managers\systemClasses\ChildManager.as:189]
           at mx.managers.systemClasses::ChildManager/initializeTopLevelWindow()[E:\dev\hero_private\frameworks\projects\framework\src\mx\managers\systemClasses\ChildManager.as:359]
           at mx.managers::SystemManager/initializeTopLevelWindow()[E:\dev\hero_private\frameworks\projects\framework\src\mx\managers\SystemManager.as:3063]
           at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::kickOff()[E:\dev\hero_private\frameworks\projects\framework\src\mx\managers\SystemManager.as:2849]
           at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::preloader_completeHandler()[E:\dev\hero_private\frameworks\projects\framework\src\mx\managers\SystemManager.as:2729]
           at flash.events::EventDispatcher/dispatchEventFunction()
           at flash.events::EventDispatcher/dispatchEvent()
           at mx.preloaders::Preloader/timerHandler()[E:\dev\hero_private\frameworks\projects\framework\src\mx\preloaders\Preloader.as:542]
           at flash.utils::Timer/_timerDispatch()
           at flash.utils::Timer/tick()
      
       
      

       

      I don't understand why I have this error when I set my custom style properties... Furthermore, before using the SkinPart feature, when I tried the same test, the border totally disappeared of the component.

      I may have misunderstood something... However, the flex 4 documentation does not treat the subject of custom style properties for SkinnableContainer except in that page :

      http://help.adobe.com/en_US/flex/using/WS2db454920e96a9e51e63e3d11c0bf687e7-7ff6.html#WS2d b454920e96a9e51e63e3d11c0bf69084-79da

      If you read the exemple in the Defining a style property you will see that it treats the case of component which manage styles and appearance itself instead of defining a style property set in the skin of the component.

       

      So:

      - can you tell me why I have the error pasted above ?

      - can somebody explain me how to define a custom property in a skinnable component (a container in my case) which can be used and set in a skin made for this component ?

       

      Thanks in advance