Hey João,
Posted online with SWF and View Source:
http://jonathanbranam.net/node/56
http://jonathanbranam.net/solutions/detect-state-addchild

There are two solutions that I've found to work in this case. This first is
to add a new public method to the component called activate() and then call
it from a handler on the
enterState<http://jonathanbranam.net/flex3anatomy/event/enterState>Event.
The second is to listen to the
addedToStage <http://jonathanbranam.net/flashphysiology/event/addedToStage>and
updateComplete 
<http://jonathanbranam.net/flex3anatomy/event/updateComplete>events,
set a flag in
addedToStage <http://jonathanbranam.net/flashphysiology/event/addedToStage>that
you check in
updateComplete <http://jonathanbranam.net/flex3anatomy/event/updateComplete>to
run your initialization.

Here is the code, example app, and more detailed explanation.

You can view the example on a separate
page<http://jonathanbranam.net/files/src/detect-state-addchild/DetectStateAddChild.html>and
view the source (View Source doesn't work in the embedded SWF below
due
to a bug in Flex Builder).

   Explanation:

The first solution is easy and should be solid. The
enterState<http://jonathanbranam.net/flex3anatomy/event/enterState>Event
fires after the component has been added to the stage (not during the
operation), so it is safer to access subcomponents. The method, however,
does not guarantee that the component has been fully updated yet. The
downside to this is adding more coupling between the
State<http://jonathanbranam.net/flex3anatomy/class/State>and the
component.

   1.     <mx:State name="solution1">
   2.       <mx:enterState>
   3.         sol1.activate();
   4.       </mx:enterState>
   5.       <mx:RemoveChild target="{noState}"/>
   6.       <mx:AddChild>
   7.         <local:Solution1VBox id="sol1"/>
   8.       </mx:AddChild>
   9.     </mx:State>

 The code in the component is equally obvious:

   1.       public function activate():void
   2.       {
   3.         ti.setFocus();
   4.       }


   1.   <mx:Label text="Solution 1"/>
   2.   <mx:TextInput text="No focus here!"/>
   3.   <mx:TextInput id="ti" text="Focus here!"/>

 The second solution relies on the behavior of the
State<http://jonathanbranam.net/flex3anatomy/class/State>AddChild
operation. AddChild is true to its name, it will add and remove the
component from the display list. This means that the
added<http://jonathanbranam.net/flashphysiology/event/added>,
addedToStage <http://jonathanbranam.net/flashphysiology/event/addedToStage>,
removed <http://jonathanbranam.net/flashphysiology/event/removed>, and
removedFromStage<http://jonathanbranam.net/flashphysiology/event/removedFromStage>methods
will fire when the state is entered and exited. The trouble is that
the component has not been fully created when these events fire. The
solution I present here is to set a flag when the component has been added
to the stage so that the component knows that it needs to run its activation
code again:

   1.       protected var addedToStage:Boolean = false;
   2.       protected function addedToStageHandler(event:Event):void
   3.       {
   4.         if (event.target == this) {
   5.           addedToStage = true;
   6.         }
   7.       }

 The next part of the solution uses the
updateComplete<http://jonathanbranam.net/flex3anatomy/event/updateComplete>event
to trigger the activation code. If the
addedToStage code has run since the most recent update, then we run the
activation code.

   1.       protected var addedToStage:Boolean = false;
   2.       protected function addedToStageHandler(event:Event):void
   3.       {
   4.         if (event.target == this) {
   5.           addedToStage = true;
   6.         }
   7.       }

 Note that 
updateComplete<http://jonathanbranam.net/flex3anatomy/event/updateComplete>fires
every time the component is invalidated through something like
invalidateDisplayList(). I put a button in the component so you can trigger
updateComplete <http://jonathanbranam.net/flex3anatomy/event/updateComplete>.
If you remove the check for addedToStage, then invalidating the component
will run the activation code again, which is not the desired behavior. See
the article on 
updateComplete<http://jonathanbranam.net/flex3anatomy/event/updateComplete>for
more information about this event.

   1.   <mx:Label text="Solution 2"/>
   2.   <mx:TextInput text="No focus here!"/>
   3.   <mx:TextInput id="ti" text="Focus here!"/>
   4.   <mx:Button label="Invalidate Component" click=
   "invalidateDisplayList()"/>

 I'm not sure which solution I like better. The first is more direct and
should be more resistant to changes in implementation or functionality. If
you move from using AddChild to toggling visibility, then you can still call
the activate() method from the
enterState<http://jonathanbranam.net/flex3anatomy/event/enterState>Event.
However, this type of change will break the second solution.

Ultimately, there isn't a single, reliable event that will tell your
component it has now become "viewable" so you have to code up individual
solutions. If you think further about things like hiding a component by
shrinking its width to 0 there just isn't a solution that would always
detect everything.
-Jonathan
http://jonathanbranam.net - Flex 3 Anatomy and Solutions

On Fri, Jun 27, 2008 at 10:33 AM, João <[EMAIL PROTECTED]> wrote:

>   Hello,
>
> I have a:
>
> - Container with two states ( "" and "editing")
> - A view (LocaleEditor.mxml) that is shown when the container changes
> to the state "editing":
>
> <mx:states>
> <mx:State name="editing" >
> <mx:RemoveChild target="{listaDeLocales}"/>
> <mx:AddChild relativeTo="{gestorDeLinguas}" position="lastChild">
> <ns1:LocaleEditor id="localeEditor"/>
> </mx:AddChild>
> </mx:State>
> </mx:states>
>
> I need my view to execute some code when it is shown
> (myTextBox.setFocus() ). I have tried the creationComplete event, but
> the view is only created on the first time the state changes, the next
> times this event is not dispatched. I have tried the AddedToStage, but
> it throws a runtime error with the myTextBox.setFocus() code . I have
> tried the "show" event, but it simply doesn't work.
>
> Which event should I rely on to execute the "myTextBox.setFocus()"
> when the user sees the view?
>
> Thanks,
>
> João Saleiro
>
>  
>

Reply via email to