[flexcoders] Which event is dispatched when the view is shown by a stage change?

2008-06-27 Thread João
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



Re: [flexcoders] Which event is dispatched when the view is shown by a stage change?

2008-06-27 Thread Jonathan Branam
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
enterStatehttp://jonathanbranam.net/flex3anatomy/event/enterStateEvent.
The second is to listen to the
addedToStage http://jonathanbranam.net/flashphysiology/event/addedToStageand
updateComplete 
http://jonathanbranam.net/flex3anatomy/event/updateCompleteevents,
set a flag in
addedToStage http://jonathanbranam.net/flashphysiology/event/addedToStagethat
you check in
updateComplete http://jonathanbranam.net/flex3anatomy/event/updateCompleteto
run your initialization.

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

You can view the example on a separate
pagehttp://jonathanbranam.net/files/src/detect-state-addchild/DetectStateAddChild.htmland
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
enterStatehttp://jonathanbranam.net/flex3anatomy/event/enterStateEvent
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
Statehttp://jonathanbranam.net/flex3anatomy/class/Stateand 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
Statehttp://jonathanbranam.net/flex3anatomy/class/StateAddChild
operation. AddChild is true to its name, it will add and remove the
component from the display list. This means that the
addedhttp://jonathanbranam.net/flashphysiology/event/added,
addedToStage http://jonathanbranam.net/flashphysiology/event/addedToStage,
removed http://jonathanbranam.net/flashphysiology/event/removed, and
removedFromStagehttp://jonathanbranam.net/flashphysiology/event/removedFromStagemethods
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
updateCompletehttp://jonathanbranam.net/flex3anatomy/event/updateCompleteevent
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 
updateCompletehttp://jonathanbranam.net/flex3anatomy/event/updateCompletefires
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 
updateCompletehttp://jonathanbranam.net/flex3anatomy/event/updateCompletefor
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
enterStatehttp://jonathanbranam.net/flex3anatomy/event/enterStateEvent.
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