Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/apache-flex/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache flex 如何使用mxml继承状态?_Apache Flex_Flex4_Mxml_States - Fatal编程技术网

Apache flex 如何使用mxml继承状态?

Apache flex 如何使用mxml继承状态?,apache-flex,flex4,mxml,states,Apache Flex,Flex4,Mxml,States,我有以下名为AdvancedPanel的面板组件,带有controlBarContent: <!-- AdvancedPanel.mxml --> <s:Panel> <s:states> <s:State name="normal" /> <s:State name="edit" /> </s:states> <s:controlBarContent> <s:Butto

我有以下名为AdvancedPanel的面板组件,带有controlBarContent:

<!-- AdvancedPanel.mxml -->
<s:Panel>
  <s:states>
    <s:State name="normal" />
    <s:State name="edit" />
  </s:states>
  <s:controlBarContent>
    <s:Button 
      includeIn="edit"
      label="Show in edit"
      />
    <s:Button 
      label="Go to edit"
      click="{currentState='edit'}"
      />
  </s:controlBarContent>
</s:Panel>

我基于AdvancedPanel创建了第二个面板,名为CustomAdvancedPanel,因为我不想重新声明controlBarContent

<!-- CustomAdvancedPanel.mxml -->
<local:AdvancedPanel>
  <s:Button includeIn="edit" label="Extra edit button" />
</local:AdvancedPanel>

这不起作用,因为CustomAdvancedPanel中的“编辑”状态没有根据编译器声明。我必须在CustomAdvancedPanel.mxml中重新声明编辑状态,如下所示:

  <!-- CustomAdvancedPanel.mxml with edit state redeclared -->
    <local:AdvancedPanel>
      <local:states>
        <s:State name="normal" />
        <s:State name="edit" />
      </local:states>
      <s:Button includeIn="edit" label="Extra edit button" />
    </local:AdvancedPanel>

在应用程序组件中使用CustomAdvancedPanel会显示一个带有“转到编辑”按钮的空面板。但是当我点击它时,“额外编辑按钮”变为可见,而控制栏中的“显示在编辑中”按钮则不可见

当CustomAdvancedPanel为空时,没有重新声明的状态和“额外编辑按钮”,面板工作正常

我认为这是因为AdvancedPanel中声明的状态对象与CustomAdvancedPanel不同,因此状态不同,即使它们具有相同的名称。然而。我无法在CustomAdvancedPanel中使用AdvancedPanel的状态,除非(重新)在mxml中声明它们


有没有办法实现这种状态重用?或者有更好的方法来获得相同的结果吗?

如果组件的状态不会转移到继承的组件上。想想看——如果是这样的话(如果你可以继承状态),那么无论何时你想要扩展一个组件,它都会让生活变得非常复杂;您必须了解所有继承的状态,而不是踩着它们的脚。

我认为这是OO编程的一个限制,但不确定具体是什么。我不是Flex专家,但我从面向对象编程的角度考虑了这一点,以下是我的想法:

首先考虑,当您创建对象时,Flex(或任何OO语言)自动创建该对象的副本和它的父对象的私有副本,而该父对象又创建其父对象的私有副本,从而在整个对象树上创建一个私有副本。这听起来可能很奇怪,但作为一个例子,当您在构造函数中编写super()时,您正在调用父类的构造函数

Flex有它所谓的“属性”。这相当于Java中使用公共getter和setter方法的私有成员字段(变量)。当你申报时

<local:states>xyz</local:states>
这反过来又相当于说

setStates(xyz)
重要的是,这是关于属性的一般规则,setStates是一个公共方法,任何人都可以调用它。但是,states数组本身是私有的。如果不声明,CustomAdvancedPanel没有states属性。它也没有setStates或getStates方法。但是,由于setStates/getStates是公共的,它从AdvancedPanel继承它们,因此它的功能就好像它有这些方法一样。当您调用其中一个方法(获取或设置states数组)时,它实际上调用它所在的方法,该方法位于其父对象AdvancedPanel中。当AdvancedPanel执行该方法时,将读取或设置AdvancedPanel本身中状态数组的值。这就是为什么当您不在CustomAdvancedPanel中重新声明任何状态时,一切都可以完美地工作-您认为您正在CustomAdvancedPanel中设置和获取状态数组,但实际上在幕后您正在AdvancedPanel父对象中操作状态数组,这非常好

现在在CustomAdvancedPanel中重新定义状态数组-发生了什么?请记住,在Flex中声明属性就像声明私有类级别变量和公共getter和setter。因此,您为CustomAdvancedPanel提供了一个名为states和public getter和setter的私有数组来获取/设置该数组。这些getter和setter将覆盖AdvancedPanel中的getter和setter。因此,现在您的应用程序将以相同的方式与CustomAdvancedPanel交互,但在幕后,您不再操作AdvancedPanel的方法/变量,而是操作您在CustomAdvancedPanel中声明的方法/变量。这解释了为什么在更改CustomAdvancedPanel的状态时,从AdvancedPanel继承的零件不会做出反应,因为其显示链接到AdvancedPanel中的状态数组,该数组仍然独立存在

那么,为什么在基本示例中不允许includeIn,即不重新声明州?我不知道。要么是一个bug,要么更可能是一个合法的语言/OO原因导致它无法工作

我的解释可能不完全准确。就我所知。考虑到这个按钮是超类的一部分,我自己也不知道为什么会发生这种情况。以下是几个有趣的测试:

  • 将单击处理程序移动到实际的公共方法中,而不是内联方法
  • 将super.currentState='edit'添加到单击处理程序
  • 如果您想进一步了解所有这些继承内容,请在ActionScript或Flex中编写一些简单的类,其中一个类继承另一个类,并运行各种函数调用以查看发生了什么。

    “或者有更好的方法获得相同的结果吗?”

    既然您提出了要求,而且由于您没有明确说明是否需要额外的CustomAdvancedPanel组件,所以在AdvancedPanel组件中放置“额外编辑按钮”是最简单的解决方案

    <!-- AdvancedPanel.mxml -->
    <s:Panel>
      <s:states>
        <s:State name="normal"/>
        <s:State name="edit"/>
      </s:states>
      <s:Button includeIn="edit" label="Extra edit button"/>
      <s:controlBarContent>
        <s:Button 
          includeIn="edit"
          label="Show in edit"/>
        <s:Button 
          label="Go to edit"
          click="{currentState='edit'}"/>
      </s:controlBarContent>
    </s:Panel>
    

    我建议您使用Spark的蒙皮架构来实现您的目标。因为皮肤状态是在主机组件中继承的,所以您可以以OOP方式放置所有逻辑。但是皮肤仍然会包含重复的代码:(无论如何,它比所有组件的重复代码要好

    因此,我们的AdvancedPanel将如下所示:

    package
    {
        import flash.events.MouseEvent;
    
        import spark.components.supportClasses.ButtonBase;
        import spark.components.supportClasses.SkinnableComponent;
    
        [SkinState("edit")]
        [SkinState("normal")]
        public class AdvancedPanel extends SkinnableComponent
        {
            [SkinPart(required="true")]
            public var goToEditButton:ButtonBase;
            [SkinPart(required="true")]
            public var showInEditButton:ButtonBase;
    
            private var editMode:Boolean;
    
            override protected function getCurrentSkinState():String
            {
                return editMode ? "edit" : "normal";
            }
    
            override protected function partAdded(partName:String, instance:Object):void
            {
                super.partAdded(partName, instance);
                if (instance == goToEditButton)
                    goToEditButton.addEventListener(MouseEvent.CLICK, onGoToEditButtonClick);
            }
    
            override protected function partRemoved(partName:String, instance:Object):void
            {
                super.partRemoved(partName, instance);
                if (instance == goToEditButton)
                    goToEditButton.removeEventListener(MouseEvent.CLICK, onGoToEditButtonClick);
            }
    
            private function onGoToEditButtonClick(event:MouseEvent):void
            {
                editMode = true;
                invalidateSkinState();
            }
        }
    }
    
    对于CustomAdvancedPanel:

    package
    {
        import spark.components.supportClasses.ButtonBase;
    
        public class CustomAdvancedPanel extends AdvancedPanel
        {
            [SkinPart(required="true")]
            public var extraEditButton:ButtonBase;
        }
    }
    
    当然可以从Panel类继承,但我使示例代码更简单

    皮肤:<
    package
    {
        import spark.components.supportClasses.ButtonBase;
    
        public class CustomAdvancedPanel extends AdvancedPanel
        {
            [SkinPart(required="true")]
            public var extraEditButton:ButtonBase;
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <!-- AdvancedPanelSkin.mxml -->
    <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx">
        <fx:Metadata>
            [HostComponent("AdvancedPanel")]
        </fx:Metadata>
        <s:states>
            <s:State name="normal" />
            <s:State name="edit" />
        </s:states>
        <s:Panel left="0" right="0" top="0" bottom="0">
            <s:controlBarContent>
                <s:Button id="showInEditButton" label="Show in edit" includeIn="edit" />
                <s:Button id="goToEditButton" label="Go to edit" />
            </s:controlBarContent>
        </s:Panel>
    </s:Skin>
    
    <?xml version="1.0" encoding="utf-8"?>
    <!-- CustomAdvancedPanelSkin.mxml -->
    <s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" 
        xmlns:s="library://ns.adobe.com/flex/spark" 
        xmlns:mx="library://ns.adobe.com/flex/mx">
        <fx:Metadata>[HostComponent("CustomAdvancedPanel")]</fx:Metadata>
        <s:states>
            <s:State name="normal" />
            <s:State name="edit" />
        </s:states>
        <s:Panel left="0" right="0" top="0" bottom="0">
            <s:Button includeIn="edit" label="Extra edit button" id="extraEditButton" />
            <s:controlBarContent>
                <s:Button id="showInEditButton" label="Show in edit" includeIn="edit" />
                <s:Button id="goToEditButton" label="Go to edit" />
            </s:controlBarContent>
        </s:Panel>
    </s:Skin>
    
            override public function set states(value:Array):void
            {
                if(super.states == null || super.states.length == 0)
                {
                    super.states  = value;
    
                    for each (var state:State in value)
                    {
                        state.name = "_"+state.name;
                    }
                }
                else
                {
                    for each (var state:State in value)
                    {
                        state.basedOn = "_"+state.name;
                        super.states.push(state);
                    }
                }
            }