如何将 MXML 子节点放入自定义 Flex 4 组件中?

发布于 2024-10-05 11:20:55 字数 568 浏览 0 评论 0原文

这是自定义组件的示例。它只是一个带有标题标签和关闭图像 (X) 的框:

<?xml version="1.0"?>
<mx:Canvas ... >
    <s:VGroup>
        <s:Label text="(HEADING TEXT)" ... />

        (INSTANCE MXML)

    </s:VGroup>
    <mx:Image ... />
</mx:Canvas>

在 MXML 文档中使用该组件时,我希望将“(HEADING TEXT)”替换为参数(应该很容易)以及带有多个标签、文本输入、复选框等的“(INSTANCE MXML)”(可能更难)。

我找到了这种基于脚本的方法,但我想要一个更干净的编译时解决方案(如果存在)。有什么建议吗?

Here is an example of a custom component. It is just a box with a title label and a close image (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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北渚 2024-10-12 11:20:55

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>

这将让您像这样传递标题文本:

 <my:MyComponent headingText="Custom Heading Text" />

您可以对要传递的其他简单值采用相同的方法;只需声明一个公共属性,使其可绑定,然后在组件中使用数据绑定将该属性挂钩到其目的地(或多个目的地)。

您可以对复杂的属性(例如 INSTANCE MXML)执行相同的操作。当您使用它时,它看起来像这样:

<my:MyComponent>
  <my:thePropertyName>
     <s:Label text="whatever..." ... />
     <(OTHER MXML CONTENT) />
  </my:thePropertyName>
  <my:someOtherPropertyName>
    ....
  </my:someOtherPropertyName>
</my:MyComponent>

有关如何实现此功能的示例,您可以查看 spark.components.Group 组件的 mxmlContent 属性弹性框架。源代码太长,无法在这里发布,而且我似乎无法找到直接指向源代码的在线链接;但基本思想是这样的(您可以在 mxml 文件中的 块内执行以下所有操作 - 您不必创建一个纯 AS 类来执行此操作):

[1]
将属性声明为 Array 类型,并使用元数据 ArrayElementType 来指示您希望数组包含的类型。

[ArrayElementType("mx.core.IVisualElement")]
public function set mxmlContent(value:Array):void {
    _mxmlContent = value;
}
private var _mxmlContent:Array;

[2] 您需要一些逻辑来在运行时循环数组,并将数组的内容添加到组件的显示列表中。 createChildren 重写是触发此操作的好地方。以下内容大致源自 Spark GroupsetMXMLContent() 方法的实现。它并没有涵盖所有可能的情况,但它会帮助您开始:

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);
    }
}

所以现在您的组件将有一个名为 mxmlContent 的属性,您可以使用以下语法从父 mxml 组件中设置该属性:

<my:MyComponent>
   <my:mxmlContent>
       ... (MXML ELEMENTS HERE) ...
   </my:mxmlContent>
</my:MyComponent> 

您可以通过应用元数据:[DefaultProperty("mxmlContent")] 您的组件类,将新属性设置为组件的默认属性。要从 mxml 执行此操作,只需将元数据定义包装在 元素中。 请参阅此处的 fx:Metadata 示例


将以上所有内容放在一起,您将得到可以像这样使用的东西:

<my:MyComponent headingText="Custom Text Here">
   (CUSTOM MXML CONTENT HERE)
</my:MyComponent>

编辑:我应该在这里做一些注释:

  1. “Halo”组件(例如mx: Canvas)不支持上面使用的 addElement(),因此您可能需要使用 addChild() 来代替。

  2. 您应该(可能)使用 Spark 组件而不是 Halo 组件。意思是,使用 作为基础,而不是 。如果您这样做,那么您的组件将继承上述的 mxmlContent 属性。如果您希望组件拥有自己的“内容”属性(甚至多个内容属性),只需将它们命名为不同的名称即可。

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:

  1. "Halo" components (like mx:Canvas) don't support addElement() as used above, so you'll probably want to use addChild() instead.

  2. 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 the mxmlContent property described above. if you want your component to have its own "content" property (or even multiple content properties), just name them something different.

病毒体 2024-10-12 11:20:55

这太棒了。感谢您提供此信息。

由于我不需要对其进行太多控制,因此我稍微简化了这个解决方案。

我们的容器 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}" />

和用法:

<myComponents:MyComponent
    xmlns:myComponents="myComponents.*"
>

    <myComponents:content>
        <s:Label />
        <s:Label />
        <AnythingWeWant...
    </myComponents:content>

</myComponents:MyComponent>

希望这对任何人都有帮助。
干杯。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文