Is there an event in Flex that shoots out when all the operations in a mx:state tag are done? - apache-flex

Let's take the next example:
<mx:State name="sayHello">
<mx:SetProperty name="preText" target="{this}" value="Hello"><mx:SetProperty>
</mx:State>
Can I somehow know when preText property has been set to hello?
Already tried with:
state->activate
state->enterState
state->exitState
and
UIComponent->currentStateChange
In all the cases above,pretext property is null, how ever somehow, later on it gets the desired value (I tested with a timer)
Any help would be great!
Thanks!

It is tough to say. Most properties implemented by the Flex Framework dispatch a propertyChangedEvent. So, in this case you could listen to preTextChanged event on the component in question to let you know that the property changed.
If this is a property you implemented yourself, just make the properties set method dispatch the event, like this:
dispatchEvent(new Event('preTextChanged'));
Add the listener like this:
this.addEventListener('preTextChanged',onpreTextChanged);
You won't be able to listen to the property change event in MXML if you don't define event metadata for the event; and most components do not bother to define metadata for the propertyChanged event.
The act of changing a state can take time. Due to the asynchronous nature of Flex/Flash Player something like this:
currentState = newState
trace(preText);
The trace value will most likely not be set yet because the state change processing did not occur yet. You may be able to listen to the currentStateChange event, thoug. When that dispatches your properties should all be modified.

Related

Can I disable CHANGE event in a custom component?

I have a custom MXML component which has a change event declared as:
<mx:Metadata>
[Event(name="change", type="flash.events.Event")]
</mx:Metadata>
The problem is that this event is dispatched whenever I change ANYTHING inside the component including a simple var. There are times when I want to be able to change the value of a var in the component without dispatching a change event. Is there a simple way of disabling the change event and then re-enabling it once I have made the change I want?
I tried to use removeEventListener("change") but it appears I can only do that for a function that has an event listener added. Same for removeEventListener(Event.CHANGE).
Surely there must be a simple way of disabling events declared in
mx:Metadata
yes there are methods on event you can use. So although the event is still dispatched, this gives you complete control of what happens with it.
// first set the useCapture flag to true
// this tell flex that onChange gets the event before it starts bubbling
myCustomComponentThatDispatchesALotOfChangeEvents.addEventListener(Event.CHANGE, onChange, true);
private function onChange(event:Event):void{
// here is the method you want
// this stops the event from bubbling and lets you handle
// all functionality in this listener only
event.stopImmediatePropogation();
// now look at what happened and see if you want to
// do anything else based on what actually changed
}
as a side note, you can also look at Event.preventDefault() which cancel's the events default behavior
"change" is also a flex thing. It you want to only dispatch the event in one particular scenario, make a new event class that SubClasses Event like MyChangeEvent. The when you make your change...
dispatchEvent(new MyChangeEvent(MyChangeEvent.STUFF_CHANGED))
then
myCustomComponentThatDispatchesALotOfChangeEvents.addEventListener(MyChangeEvent.STUFF_CHANGED, onChange);

Is there a reliable way to "refresh" a component?

By "refresh" I am completely disposing it and then introducing it again in the application (without closing the application itself - that is). Other than than I think the question is self-explanatory.
Example:
Say I have a component named myComponent. I add that component to the application using MXMl in the standard way <components:myComponent id="myID" />. Say that when a user clicks a button (the button may be in another state), the component with id myID should be garbage-collected and a new instance of it added to the application.
How do I go about doing that? If there are multiple solutions which one is the optimal performance-wise?
I am new to Flash and Flex so excuse me if any incorrect terminology were used.
Remove all the event listeners from the old component; whatever they are using the removeEventListener method:
myButton.removeEventListener(someEvent, someEventHandlerMethod);
Then all variables that refer to the component should be set to null. If created in an MXML file, like this:
<s:Button id="myButton" />
Then all you have to do is set that value to null:
myButton = null;
Once there are no references to the component, it can safely become eligible for garbage collection.
If you want to re-created, then just re-created it. You'll have to re-create it in ActionScript, but the code isn't hard. Conceptually something like this:
myButton = new myButton();
myButton.properties = propertyValues;
myButton.addEventListener(someEvent, someEventHandlerMethod);
parentContainer.addChildAt(myButton, whateverPositionYouWantToADdTheComponentAt);
I'm not sure I see the benefit of doing this. I suspect it'll be much more efficient to tweak the existing button instance in the way you need to as opposed to destroying it and trying to replace it with the exact same thing.

Why does BindingUtils.bindProperty() not work immediately?

I have a two way binding between a loaded flash file and the main application in flex.
BindingUtils.bindProperty(this, "micGainValue", audioPublisherApp, "micVolume");
BindingUtils.bindProperty(audioPublisherApp, "micVolume", this, "micGainValue");
micGainValue=75;
However, the setting of micGainValue does not set micVolume in the flash file. I instead tried setting micGainValue after 200 frames, and it now does set micVolume. Is there a way to test that these properties are bound and so set the value after?
EDIT:
The flash file was actually changing the value. Now the question is, why does setting micVolume not change micGainValue.
This the code from my loaded flash file:
[Bindable]
public function get micVolume():Number{
if(microphone!=null)
return microphone.gain;
return 0;
}
public function set micVolume(val:Number):void{
if(microphone!=null)
microphone.gain=val;
}
Flex databinding is implemented using events. When you use BindingUtils.bindProperty, what is happening behind the scenes is that an event listener is being added to the target object to listen for an event of type PropertyChangeEvent
If the target object does not dispatch the PropertyChangeEvent when it is changed, then binding will never be triggered.
When you add the [Bindable] attribute to properties in Flex, what you are doing is telling the framework to dispatch the PropertyChangeEvent when that property is changed. If you don't include the attribute (or put it on the class) then the event is not dispatched and binding doesn't happen.
That's why your binding is working from Flex to Flash but not the other way around- The Flex object is dispatching the required event when it is changed but the flash object is not.
Here is the info on PropertyChangeEvent
Personally, for Flash -> Flex I would dispatch my own event when the flash part changes its values and use a handler on that to update a bindable object within the Flex part. You can then bind other Flex stuff to that.

Howto removeEventListener with <mx:SetEventHandler />?

I'm trying to remove an eventlistener on (in this specific case) a HorizontalList. The list is initialized with the property
itemRollOver="playPreview(event)"
I'd like to remove this eventListener by switching state and stating something like:
<mx:SetEventHandler target="{horList}" name="itemRollOver" handlerFunction="null" />
This doesn't seem to work. The event is still handled and playPreview(event:ListEvent) is still called. How to properly do this? (I know I can do it in Actionscript, but I specifically want to do it by means of state switching)
Cheers Bart
AFAIK you can only remove listeners that were added with AS, not ones added with mxml. So you should remove the listener from the mxml, on creationComplete of your app use AS to add the event listener, then whatever you do to cause your state to switch can fire an AS function to remove it.
Of the top of my head the code is something like this:
HList.addEventListener(MOUSE_EVENT.RollOver,nameOfRollOverFunction);
HList.removeEventListener(MOUSE_EVENT.RollOver,nameOfRollOverFunction)

Flex 3 keyboard event handling

I'd like to arrange things so that I have a chain of keyboard event handlers in my flex application, all of whom are queried when key down events occur. Basically, when a visual component is on screen, it is a candidate for handling a key press event. Something like this (clearly this is pseudocode):
<application handles_keys="F5, F6">
<tabGroup>
<tab1 handles_keys="pgup, pgdn">
<control handles_keys="0,1,2,3,4,5,6,7,8,9" />
</tab1>
<tab2 handles_keys="pgup, left, right"/>
</tabGroup>
</application>
I have a class written that will respond to the key events the way I want it to, so how do I register one or more instances of this class to have the results I want? Also, note that there are some situations where this class should receive events that would ordinarily be handled by a UI component. The TAB key is the main example; I have a few cases where I want my key down event handler to fire even when the focus is on a text field.
The way you have your pseudocode setup right now, you'd have to subclass all the different containers and add a handles_key property to each one. You may want to externalize the functionality to a separate class like this:
<KeyHandler target="{tab1}" handlesKeys="pgup,left,right"/>
As for actually catching the events, you'll need to add a KeyboardEvent.KEY_DOWN listener on the UIComponent you're wanting to listen to. You'll need to set the useCapture argument of addEventListener() to true as well. This will let you capture the event and prevent it instead of the event hitting the object and bubbling up.
target.addEventListener(KeyboardEvent.KEY_DOWN, target_onKeyDown, true);
Inside your target_onKeyDown event, check to see if you have a match for one of your keys you want to handle and if there is a match, call event.stopImmediatePropagation() or event.preventDefault() depending on what you need to do.
The Flex 3 Language Reference gives a good explanation of event propagation and keyboard events:
http://livedocs.adobe.com/flex/3/langref/flash/events/Event.html
The correct approach turns out to have been a global keyboard event manager, added as a key down listener to the stage when the application's creationComplete event is called. This then dispatches domain events for each keypress or combination thereof. Sadly, the filtering per-component model didn't work out.
I'm going to be porting this app to the Cairngorm framework, which should work really well once I'm done it.
when the displayed object is added to screen then start listen for stage keyboard events
when the object was removed from the screen the remove the keyboard event listener
on keyboard events filter the events you need :)
The code for a Canvas class you need should look like this:
class MyCanvas extends Canvas
{
public function MyCanvas(){
super();
}
override protected function createChildren():void{
super.createChildren();
this.systemManager.stage.addEventListener(KeyboardEvent.KeyUp, onKeyUpHandler);
}
private function onKeyUpHandler(e:KeyboardEvent):void{
// handle your code
switch(e.charCode){
case Keyboard.1:
case Keyboard.2:
case Keyboard.3:
case Keyboard.4:
case Keyboard.5:
case Keyboard.6:
case Keyboard.7:
case Keyboard.8:
case Keyboard.9:{
// do my stuff
break;
}
case Keyboard.F1:{
// do other stuff
break;
}
}
}
}
public function destroy():void{
//don't forget to remove listeners for stupid flash garbage collector
this.systemManager.stage.removeEventListener(KeyboardEvent.KeyUp, onKeyUpHandler);
}
}
Ignore any miss-spells :D I wrote the code from my mind :))

Resources