views:

77

answers:

2

I have the following panel component called AdvancedPanel with 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>

I created a second panel, called CustomAdvancedPanel based on the AdvancedPanel since I don't want to redeclare the controlBarContent

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

This doesn't work, because the 'edit' state in CustomAdvancedPanel isn't declared according to the compiler. I have to redeclare the edit state in CustomAdvancedPanel.mxml as follows:

  <!-- 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>

Using the CustomAdvancedPanel inside an application component shows an empty panel with the "Go to edit" button. But when I click it, the "Extra edit button" becomes visible, but the "Show in edit" button inside the controlBar doesn't.

When the CustomAdvancedPanel is empty, without redeclared states and "Extra edit button" the panel works just fine.

I think it is because the State object declared in AdvancedPanel isn't the same as CustomAdvancedPanel, so the state is different, even if they have the same name. However. I can't use the states of AdvancedPanel inside CustomAdvancedPanel without (re)declare them in mxml.

Is there any way to achieve this kind of state-reuse? Or is there a better way to obtain the same result?

A: 

AFAIK the component's state does not cross over to inherited components. Think about it - if that were the case (if you could inherit states) then it would make life really complicated whenever you want to extend a component; you would have to be aware of all inherited states and not step on their toes.

Assaf Lavie
Adding <mx:DataGrid dataProvider="{new ArrayCollection(states)}" /> in the CustomAdvancedPanel without redeclaring the states returns the three states from AdvancedPanel (normal, edit, disabled)However. You can't use them in mxml, because the compiler says they aren't there, but they are as the datagrid suggests.
Treur
A: 

I reckon it's a limitation of OO programming, but not sure what exactly. I'm no Flex expert but I thought about it from an object-oriented programming point of view and here's what I think happens:

First consider that when you create an object, Flex (or any OO language) automatically creates a copy of that object AND a private copy of its parent object, which in turn creates a private copy of its parent object and so on up the entire object tree. That might sound weird but as an example of this, when you write super() in a constructor you are calling the constructor of the parent class.

Flex has what it calls "properties". This is the equivalent of what in Java would be a private member field (variable) with a public getter and setter method. When you declare

<local:states>xyz</local:states>

you are effectively saying

states = xyz

which in turn is the AS equivalent of saying

setStates(xyz)

The important part, and this is a general rule about properties, is that setStates is a public method, anyone can call this. However the states array itself is private. If you don't declare one, CustomAdvancedPanel has no states property. Neither does it have a setStates or getStates method. However as setStates/getStates are public, it inherits them from AdvancedPanel so it funcions as if it has these methods. When you call one of these methods (get or set the states array), it actually calls the method where it exists, which is in its parent object, AdvancedPanel. When AdvancedPanel executes the method the value of the states array in AdvancedPanel itself is read or set. This is why when you don't redeclare any states in CustomAdvancedPanel everything works perfectly - you think you are setting and getting the states array in CustomAdvancedPanel but in fact behind the scenes you are operating on the states array in the AdvancedPanel parent object, which is perfectly fine and good.

Now you redefine the states array in CustomAdvancedPanel - what is happening? Remember that declaring a property in Flex is like declaring a private class-level variable and public getters and setters. So you are giving CustomAdvancedPanel a private array called states and public getters and setters to get/set that array. These getters and setters will override the ones from AdvancedPanel. So now your application will interact with CustomAdvancedPanel the same way but behind the scenes you are no longer operating on the methods/variables of AdvancedPanel but rather on the ones you have declared in CustomAdvancedPanel itself. This explains why when you change the state of CustomAdvancedPanel, the part that is inherited from AdvancedPanel does not react, since its display is linked to the states array in AdvancedPanel, which still exists independently.

So why isn't the includeIn allowed in the basic example where you don't redeclare the states? I don't know. Either it's a bug, or perhaps more likely, there's a legitimate language/OO reason why it could never work.

It's possible that my explanation is not totally accurate. That's as far as I understand things. I myself don't know why that would really happen considering the Button in question is part of the superclass. A couple of interesting tests would be:

  1. move the click handler into an actual public method instead of inline.
  2. add super.currentState='edit' to the click handler.

If you want to learn more about all this inheritance stuff, write some simple classes in ActionScript or Flex with one class inheriting another, and run various function calls to see what happens.

Fletch