A common complaint among Flex component developers is that too many of the methods in the Flex component framework are marked private instead of protected. Here’s why I’m making that complaint again today:

What I wanted to do
I wanted to make a component called SideStack that extends ViewStack. The SideStack would layout its children like an HBox by using the BoxLayout utility class. I wanted to extend ViewStack because it already has a lot of the other features I wanted: history management, the ability for developers to add children declaritively in MXML, deferred instantiation, etc.

When the user would change the selectedChild, I would leave the previously selectedChild visible and use AnimateProperty to slide the newly selectedChild into position. The layout part worked great, but preventing the previously selected child from being hidden is where the problems started.

Why I couldn’t do it the way I wanted
In ViewStack.commitProperties, there’s a call to a private method called commitSelectedIndex. This is where the previousChild.setVisible( false ) happens. Unfortunately, the commitSelectedIndex method is marked private, so I can’t override it. That started the following frustrating process:

Failed work-around #1
My first thought was, “Well, I’ll just override commitProperties, copy the stuff I need from ViewStack.commitProperties, and I’m good.” The problem is, I need to prevent the code in ViewStack.commitProperties from running but I need Container.commitProperties to execute. In other words, instead of this:

//SideStack.as

override protected function commitProperties():void
{
super.commitProperties();

//copied & modified code from ViewStack.commitProperties
}

I would need to do something impossible, like this:

override protected function commitProperties():void
{
super.super.commitProperties();

//copied & modified code from ViewStack.commitProperties
}

So, back to the drawing board.

Failed work-around #2
My next try was to temporarily set the flag that causes commitSelectedIndex to get called to a value that would cause that block to get skipped. In other words, I would set proposedSelectedIndex to -1 before I called super.commitProperties(). Nope. proposedSelectedIndex is private too, so I can’t do that.

Crazy, ugly work-around attempt #3
Out of frustration, I decided to copy & paste all the ViewStack code into my SideStack class instead of extending it. I know, I know. But I can’t do that because I want to be able to bind the dataProvider of a ButtonBar, LinkBar, or TabBar to the component and that would require a ViewStack or a subclass.

Pending ugly work-around attempt #4
Once I take a little break, I’m going to try to do previousChild.setVisible( true ) after ViewStack sets it to false. That might get me a little bit further, but I’m afraid of another roadblock. And that’s a fairly ugly hack.

If that fails
I’ll give up and just use a different version that extends HBox and, over time, I’ll add the features like historyManagement and stuff later. :(

If the framework was open source right now
I would be tempted to just edit ViewStack.as and change commitSelectedIndex to protected, but then I’d be the only one that could use my component.

Anybody have a magic solution?

Any Adobe engineers care to comment?

10 Responses to “My frustrating experience trying to extend ViewStack”

  1. Doug Says:

    One problem you were having is you didn’t want to copy/paste ViewStack because you wanted to be able to set your component as the dataprovider of ButtonBar, TabBar, etc. (all with base class of NavBar). NavBar also supports setting the dataprovider to a class that implements IList. So you might be able to get *some* of the functionality you’re looking for by copy/pasting ViewStack and extending it to implement IList. It’s not the same as setting the dataprovider to be a ViewStack, but it might get you enough of what you want.

    Gotta love private methods and variables. w00t

  2. Doug Says:

    Another possibility: ViewStack’s commitSelectedIndex() function bails out if numChildren == 0, so how about overriding the getter for numChildren in your subclass? Use a private flag that you set right before super.commitProperties. If that private flag is set to true then numChildren will always return 0. Then set the flag back to false after the super.commitProperties call.

  3. tombray Says:

    Hey Doug,

    Thanks for the ideas. The numChildren == 0 hack is clever, but unfortunately most of the other properties I need to use are private too, so it looks like a lost cause.

    I’ll copy & paste and implement IList and see how that goes.

  4. judah Says:

    Hi Tom,

    I blogged on this issue here http://www.judahfrangipane.com/blog/?p=77.

  5. tombray Says:

    Hi Judah,

    That’s interesting and worth a try. It makes one’s inner object-oriented purist cringe, but it seems like it will get the job done. I’ll report back on my findings.

    -Tom

  6. tombray Says:

    Hi Judah,

    Your solution doesn’t work in my case. I need to override a private method in the super class, and it doesn’t look like your trick lets me do that.

    -Tom

  7. Steve Says:

    This might help (or at least open Pandora’s Box a smidge wider): http://blogs.digitalprimates.net/codeSlinger/index.cfm/2007/4/3/Flex-Component-Development

  8. tombray Says:

    Hi Steve,

    Yeah, I was hoping to create a component that I could distribute as open source, so I want to avoid that approach. I’ve been making progress with an alternates solution that involves copying some of the code I need from ViewStack. It won’t be too ugly, but it could’ve been so easy had I been able to override the private stuff in ViewStack. Oh, well.

    -Tom

  9. Raghu Says:

    Hi Tom,

    Flex is going Open source. So that gives you a lot of options :)
    About your problem, the issue has been logged in the Flex bugbase and is being tracked.

    Raghu

  10. tombray Says:

    Hi Raghu,

    I’m psyched that Flex is going open source. The problem is that my intention with this component was to create something that I could distribute to the community. If my component required developers to hack their SDK and replace ViewStack.as with mine, that would suck. I’m really curious how changes to the SDK from the community are going to be dealt with. Won’t Adobe be inundated with people changing private to protected?

    -Tom

Leave a Reply