Here is an example of a custom component. It is just a box with a title label and a close ima开发者_如何转开发ge (X):
<?xml version="1.0"?>
<mx:Canvas ... >
<s:VGroup>
<s:Label text="(HEADING TEXT)" ... />
(INSTANCE MXML)
</s:VGroup>
<mx:Image ... />
</mx:Canvas>
When using the component in an MXML document, I would like to have the "(HEADING TEXT)" replaced with a parameter (should be easy) as well as the "(INSTANCE MXML)" with several labels, text inputs, check boxes, etc. (maybe harder).
I have found this script-based method, but I would like a cleaner compile-time solution if one exists. Any suggestions?
MyComponent.mxml:
<?xml version="1.0"?>
<mx:Canvas ... >
<fx:Script>
[Bindable]
public var headingText:String = "Default Heading Text";
</fx:Script>
<s:VGroup>
<s:Label text="{headingText}" ... />
(INSTANCE MXML)
</s:VGroup>
<mx:Image ... />
</mx:Canvas>
That will let you pass in the headingText like this:
<my:MyComponent headingText="Custom Heading Text" />
You can follow the same approach for other simple values you want to pass in; just declare a public property, make it bindable, then within your component, use data binding to hook the property to its destination (or destinations).
You can do the same thing for complex properties (like your INSTANCE MXML). It looks like this, when you use it:
<my:MyComponent>
<my:thePropertyName>
<s:Label text="whatever..." ... />
<(OTHER MXML CONTENT) />
</my:thePropertyName>
<my:someOtherPropertyName>
....
</my:someOtherPropertyName>
</my:MyComponent>
For an example of how to implement this, you can check out the mxmlContent
property of the spark.components.Group
component in the flex framework. The source is too lengthy to post here, and I can't seem to find an online link directly to the source; but the basic idea is this (you can do all the following inside a <fx:Script>
block in an mxml file - you don't have to make a pure AS class in order to do this):
[1]
declare the property as type Array
, with metadata ArrayElementType
to indicate the type you want the array to contain.
[ArrayElementType("mx.core.IVisualElement")]
public function set mxmlContent(value:Array):void {
_mxmlContent = value;
}
private var _mxmlContent:Array;
[2] You'll need a little bit of logic to loop over the array at runtime, and add the array's contents to the component's display list. The createChildren
override is a good place to trigger this. The following is derived loosely from the implementation of setMXMLContent()
method of spark Group
. It doesn't cover all possible cases, but it'll get you started:
override protected function createChildren():void {
super.createChildren();
if( _mxmlContent == null ) return;
for (i = 0; i < _mxmlContent.length; i++) {
var elt:IVisualElement = _mxmlContent[i];
addElement(elt);
}
}
So now your component would have a property called mxmlContent
, which you could set from a parent mxml component using the syntax:
<my:MyComponent>
<my:mxmlContent>
... (MXML ELEMENTS HERE) ...
</my:mxmlContent>
</my:MyComponent>
You can make your new property into the default property
of your component, by applying the metadata: [DefaultProperty("mxmlContent")]
your component class. To do this from mxml, just wrap the metadata definition in an <fx:Metadata>
element. see here for example of fx:Metadata.
put all the above together, and you'll get something you can use like this:
<my:MyComponent headingText="Custom Text Here">
(CUSTOM MXML CONTENT HERE)
</my:MyComponent>
Edit: I should make a couple of notes here:
"Halo" components (like
mx:Canvas
) don't supportaddElement()
as used above, so you'll probably want to useaddChild()
instead.You should (probably) be using spark components instead of halo components. Meaning, use
<s:Group>
as your base instead of<mx:Canvas>
. If you do this, then your component will inherit themxmlContent
property described above. if you want your component to have its own "content" property (or even multiple content properties), just name them something different.
This is awesome. Thanks for this info.
Since I didn't need so much control over it I've simplified this solution a little.
Code for our container MyComponent.mxml:
<s:Group ... >
<fx:Script>
<![CDATA[
[Bindable]
[ArrayElementType("mx.core.IVisualElement")]
public var content:Array;
]]>
</fx:Script>
<s:Group width="100%" height="100%" mxmlContent="{content}" />
And usage:
<myComponents:MyComponent
xmlns:myComponents="myComponents.*"
>
<myComponents:content>
<s:Label />
<s:Label />
<AnythingWeWant...
</myComponents:content>
</myComponents:MyComponent>
Hope this helps anyone. Cheers.
精彩评论