Why does BindingUtils.bindProperty() not work immediately? - apache-flex

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.

Related

Setting bindable value to label in Actionscript (no curly brackets in mxml)

I've got a model class with custom change events, which is working fine if I make a reference to that class in my mxml using;
[Bindable] private var firstClass:FirstClass;
The objects gets filled by a server side script, so don't worry, firstClass isn't null.
Anyhow, accessing firstClasses properties in mxml works perfectly fine using curly brackets. The binding works just as expected.
However, is there any way to access firstClasses properties and set them to say a label with pure Actionscript.
lblTest.text = firstClass.property;
The code above doesn't work. I suppose because it sets a fixed value to the label.
I'm aware of using BindingUtils.bindProperty to explicitly set the source and destination for the binding. However, this turned out to cause huge performance issues in my (mobile) application.
So is there a simpler, more efficient way to do this?
No. The BindingUtils uses propertyChanged events to detects when an object's property changes. You won't be able to bind something without listening to events, and the most painless way to do it is using BindingUtils.

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

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.

call flex initComplete at a specific time

Below is the overriden on complete function for a preloader in Flex.
private function initComplete(e:Event):void
{
//dispatchEvent(new Event(Event.COMPLETE));
cp.status.text="Configuring... Please Wait";
}
What I want to do is when the app has finsihed loading I want to change the preloaders text to "configuring".
Then I want to go and do a bunch of setup stuff in my code.
Once I've done all the setup I wanted how can I get the Preloader to dispatch its Event.complete from else where in my code?
I tried Application.application.preloader but it comes up null.
So I guess my question really is how to access a preloader from anywhere in my application.
Would a better approach be to have all setup classes as members of my preloader class?
One thing that might help is a Model-View-Controller pattern. Are you using a framework for your application like Mate, Swiz, or Cairngorm?
If you were using Mate, for example, you could do something like this:
Create an AppStateManager class with a property (e.g. applicationState)
Create an EventMap with an EventHandler for the FlexEvent.INITIALIZE event. In this handler, set the AppStateManager.applicationState to something like "CONFIGURING"
Your EventMap has an injector that injects the applicationState property into a view. The injector listens for changes to this property and updates the view. In this case it might just be injected into your main view.
In the main view, you have a public bindable property also called applicationState that gets injected by Mate.
In the setter for this property, you can have an if/then or a switch that does different tasks depending on the state. For example, if applicationState == "COMPLETE", then this.preloader.dispatchEvent(Event.COMPLETE) or something like that.
The details are pseudo-sketched out but the idea is to use Flex's bindings to notify view components when changes have been made, and to have shared objects that maintain state. Not sure if that's what you're looking for...
The component LifeCycle does specific stuff in a specific order, and the near final element is to make the component visible.
It sounds to me like you want to defer this setting of visible to true to do other stuff. But, I imaging if you were making use of the component LifeCycle this would be a non-issue.
What sort of app init stuff do you need to do?

Flex and fake Mxml initialisation without actually showing the component, (more insise)

I have a TitleWindow mxml class wich has several components, and listeners.
On its creationComplete and init state i add some listeners which listen for events on its gui.
This TitleWindow is only shown when the user click on a "button", i made TitleWindow a singleton with the following code:
public static function getInstance():MyWindow
{
if ( MyWindow.singleton )
{
return MyWindow.singleton;
}
else{
MyWindow.singleton = new MyWindow();
return MyWindow.singleton;
}
}
I needed a singleton because the user will call this window several times as much as he wants and i only need one.
The problem is the following on some special external events i need to "modify" some listeners (remove listeners and add new ones) on a button from MyWindow, before it was even shown once.
I still have MyWindow.getInstance() in memory when my application starts up.
However adding /removing listeners does not seem to have any effect if he actual rendering of the components did not happen, event when using the following code on app startup.
myWindow= MyWindow.getInstance();
myWindow.initialize();
Not suprisingly if i "show" ('render') the myWindow at least once then the events modifications on the myWindow instance works perfectly.
How can i fake the complete initialisation of this component without showing it on startup ?
Thanks !
Which sort of a container holds your button? If you are using a Multiple View Container you can try setting the creationPolicy to all. Single View Containers create all their children in one go and you shouldn't face this problem.
From Flex 3.0 docs I could retrieve this:
The default creation policy for all containers, except the Application container, is the policy of the parent container. The default policy for the Application container is auto.
This looks like the cause for all your troubles.
Update: I did not mention this earlier, since I thought this was to be expected :) Setting the creationPolicy to all makes your application load more slowly. So, read up on Ordered Creation -- this technique helps you to choose if the controls are displayed all in one go (which is the default behavior, after all of the controls have been created) or step-by-step, as and when they are created.

Error #2099: The loading object is not sufficiently loaded to provide this information

I have a Flash app made up of AS3 components that I am trying to run in Flex.
In Flash, after the main component is added to the stage, the loader object (loaderInfo.loader) is null which is fine and I handle that.
In Flex, on the applicationComplete event I add the the main component to the stage and the loader object's getter throws an exception - Error #2099: The loading object is not sufficiently loaded to provide this information.
Also, the INIT event, which is dispatched when the properties and methods of a loaded SWF file are accessible, is not firing which is probably part of the problem. But I can't figure out why it is not being dispatched.
Any ideas why the same code has two different results?
Mmm, that seems like a frustrating problem. When you say "main component", I presume you mean the document class in Flash?
I'm not sufficiently knowledgeable about flex to comment on the problem you described, but I can suggest that you try using ADDED_TO_STAGE instead of INIT as your event...
public class MainFlashClass extends Sprite {
public function MainFlashClass() {
addEventListener(Event.ADDED_TO_STAGE, onInit);
}
public function onInit(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, onInit);
// do your initialisation code here
}
}
This might work for both scenarios. I've found ADDED_TO_STAGE to be more helpful because it always gets fired, whether the class is already loaded when the swf is executed (like the document class), or if it's being loaded with a Loader.
I'm not sure if this is what's going on with INIT event, but I do know that in flash player 9, which I'm assuming is the version of your SWF? There's a bug with referencing the loader through its own evt target. Basically if you are loading something and you try and access properties of the loader though evt.target.loaderInfo.loader it never can find itself and throws the error you described in your question. I believe it's a known bug for flash player 9 that was fixed with the release of CS4 and flash player 10.
Here's a link to a thread describing some of the problem, hopefully it helps
http://www.actionscript.org/forums/showthread.php3?t=137599
You definitely need to post code so we an see better.
With that said, after addChild are you attempting to grab the loaderInfo for the "main component" or for your mx:Application?
Pseudo
//onApplicationComplete event handler
var myswf:SWFLoader = new SWFLoader();
myswf.load(...);
addChild(nmyswf);
trace(myswf.loaderInfo.loader);
//end onApplicationComplete
Is that what you're doing? If so, you need to add an event listener to your "main component" (assuming an externally loaded swf) to find out when Event.COMPLETE happens.
var myswf:SWFLoader = new SWFLoader();
myswf.addEventListener(Event.COMPLETE, onMySWFComplete);
//..rest of code
Hope that helps. If not, post code.

Resources