How to add MXML components to an ActionScript application? - actionscript-3

I'm building an ActionScript 3 project, and have found that writing some components in MXML would simplify things.
It seems like I'd need to extend the Flex Application class in order to do that. If that is right, how should I do that?
Currently my Main object extends Sprite. Other Sprites are then added to it with addChild(), and I'd like Flex components in one of those. Surely there is a way without rewriting my application completely in MXML?

Edit As posted in the comments my explanation here is mostly regarding transitioning to a Spark application, the same kinds of ideas apply going to MX Application except with MX you could stick with addChild, generally speaking there you would need to implement IUIComponent to use containers see docs:
Note: While the child argument to the method is specified as of type
DisplayObject, the argument must implement the IUIComponent interface
to be added as a child of a container. All Flex components implement
this interface.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/Container.html#addChild()
End Edit
You can switch your base class to Application instead of Sprite, but when adding elements to a Flex 4 application it expects that they implement IVisualElement. Generally speaking you would switch your addChild calls to addElement, and you would have to change your other classes that currently extend Sprite/MovieClip/DisplayObject to extend something like Group so that they implement the necessary interfaces for Flex Application to work with them (generally it expects more things than lower level Flash objects provide since it has the LayoutManager, PopUpManager, Component Life cycle, etc.). The issue here is you'll be adding some weight to your components, if this is meant for the web or desktop I wouldn't be too concerned but this will affect performance on mobile devices, noticeably.
Unfortunately it's not a turn-key type solution, it requires some manual modification of the code since you have to make the call on what to change each object to based on it's functionality, sometimes Group is the right way to go other times you might get more benefit out of other containers or controls. In some cases you may want to stick with your current lower level extension (say extending Sprite) and just implement IVisualElement yourself.
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/mx/core/Container.html#addElement()
If you wanted to wholesale switch to using an MXML file for your application you could also create a basic MXML application file, and have it include a script block with your existing code (modified so constructor code is moved into creation complete). Alternatively you can have a base .as file that extends application then use that as the base class for your MXML, I'll throw together some examples.
Example 1 A very basic MXML Application file
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
]]>
</fx:Script>
</s:Application>
Example 2 An AS3 Class extending application and an MXML class extending that
[Main.mxml]
<?xml version="1.0" encoding="utf-8"?>
<MyBaseApp
xmlns="*"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<s:Button id="btnControl"/>
</MyBaseApp>
[MyBaseApp.as]
package
{
import mx.events.FlexEvent;
import spark.components.Application;
import spark.components.Button;
public class MyBaseApp extends Application
{
public var btnControl:Button;
public function MyBaseApp()
{
super();
addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
}
private function creationCompleteHandler(event:FlexEvent):void
{
btnControl.label = "something I set in AS3";
}
}
}

Related

How to use an MXML component in my as3 code?

I have made a lot of research on this topic but I could not find any helping answer to my issue. I currently have a 100% as3 application. I would like to add a spark component to my stage eg a datagrid (because it is way more simple and clean to create it with mxml).
FileName : MXMLPractice.mxml
<?xml version="1.0" encoding="utf-8"?>
<s:DataGrid x="0" y="0" width="50" height="50"
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<s:columns>
<s:ArrayList>
<s:GridColumn dataField="dataField1" headerText="ColumnName1"></s:GridColumn>
<s:GridColumn dataField="dataField2" headerText="ColumnName2"></s:GridColumn>
<s:GridColumn dataField="dataField3" headerText="ColumnName3"></s:GridColumn>
</s:ArrayList>
</s:columns>
</s:DataGrid>
How can I add this component to the stage in my as3 code?
Given my difficulties to find a matching answer, I guess I might be trying to do something not recommended. If that is the case, could you please advise me what to do instead?
My tests so far (compiling but not displaying anything) :
package
{
import flash.display.Sprite;
import mx.events.FlexEvent;
public class Main extends Sprite
{
private var practice:MXMLPractice;
public function Main()
{
practice = new MXMLPractice();
stage.addChild(practice);
}
}
}
In pure AS3 project, you should use AS3 components, that also extend UIComponent as flex components, but designed for pure as3 project. For this task, you will need fl.controls package. You can copy/past ui classes from the installation directory of Flash Professional:
c:\Program Files\Adobe\Adobe Flash CC\Common\Configuration\Component Source\ActionScript 3.0\User Interface\
Next step will be export view representation of ui components to the library in Flash IDE from components window CTRL+F7
It's really hard task.
If you want to use some simple class from Flex SDK like ObjectUtil just copy it to your classes. It will work fine because doesn't have imports.
But visual components are linked with many other classes. For components like grid you have to copy dozens of classes. Each of them also have dependencies and so on.
Probably it's better to modify Flash component or find open source solution.

Flash Builder (Flex) Air Project mx.* libraries swc Class mx.logging.targets::LineFormattedTarget could not be found

A teammate on my project added a swc that had some mx logging classes in it, and now my project won't compile. Error:
Class mx.logging.targets::LineFormattedTarget could not be found.
I'm on the latest Flash Builder 4.6, fresh install. I notice when I go to project > properties > Actionscript Compiler then select Libraries, there is no options to select MX like there was before. Anybody know how to solve this problem. I thought the idea behind swc's is that they are self-contained and wouldn't need to me add extra imports. Thanks.
Yah very strange... so after discussing above a bit I threw together a sample project and this compiles fine against the 4.6.0 SDK I'm using, I can see the LineFormattedTarget class within my framework.swc when I expand it in the libraries in the navigator on the left:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="windowedapplication1_creationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.core.mx_internal;
import mx.events.FlexEvent;
import mx.logging.targets.LineFormattedTarget;
protected function windowedapplication1_creationCompleteHandler(event:FlexEvent):void
{
var test:LineFormattedTarget = new LineFormattedTarget();
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:WindowedApplication>
I would check to make sure it shows the framework.swc inside of the 4.6 referenced library, if the swc isn't there try removing and re-adding the framework to the library path, if that fails with the same result I would look at pulling down the SDK fresh.

Obtain reference to View in ActionScript class within ViewNavigatorApplication

I've got a very simple project in FlashBuilder 4.5. It's a mobile application of type ViewNavigatorApplication with a single view, MapView. In the MapView.mxml file, I've got a Flex component of type Map declared in xml.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009" name="CatBusMapView">
<fx:Script>
<![CDATA[
import com.esri.ags.Map;
....
]]>
</fx:Script>
<fx:Declarations>
....
</fx:Declarations>
<esri:Map id="cbm">
...
</esri:Map>
</s:View>
In this same project, I've an actionscript class called UserGeolocation. In this class, I'm attempting to get a reference to this map component.
So far, I can get a reference to the top-level application, its ViewNavigator and the NavigationStack of said ViewNavigator. However, I cannot find a way to access the MapView, much less the map I've declared within it.
I'm aware of methods like firstView() and activeView(), but I want an absolute solution, one that retrieves the view regardless of whether or not it's first or active. I've tried navigator.getChildByName("MapView") with no luck.
You could also do it using events. Fire a custom event from the MapView onActivate/creationComplete, and pass the esri map component cbm as the data part of the event.
Have a listener in the main ViewNavigatorApplication class that listens for this event. In the handler of the event listener, you can access this through event.data, and then assign it to a variable declared in the main class or in the UserGeolocation class.
Brian
Just to underscore the original intent of the question: I want an absolute reference to a View in a ViewNavigatorApplication. I'm surprised there's no clear way of doing this in the API, since it seems common practice to put Flex components in Views, in the form of declarative MXML. Existing methods that manipulate the stack aren't helpful in this regard, because they are either a) conditional upon the active or first view, or b) affect the visual presentation of the application.
There are three general solutions that have been suggested which, oddly enough, focus on problems engendered by multiple stacks in TabbedViewNavigatorApplication and don't mention the ViewNavigatorApplication.
Put the object/component you want access to at the top of the container hierarchy (ie FlexGlobals.topLevelApplication)
Use a lightweight framework
Use events (either custom or existing)
I opted for the first.

Calling a method from a mxml component that is created from an as3 class?

Okay, I've always just developed my projects in as3 instead of mxml and I usually just setup my application to run a main actionscript file as my main doc root, sort of like how you do it in flash but in flash builder I do something like this:
<s:Application
xmlns:fx="http://ns.adobe.com/mxml/2009"
.....etcetc
>
<com:MyAS3DocClass>
</com>
<fx:Script>
<![CDATA[
public function call_from_outside():void
{
//Some code stuff here...
}
]]>
</fx:Script>
</s:Application>
Now say MyAS3DocClass has a public function within it:
public function hitme():void
{
trace('ouch');
}
My question is, how can I call place a call to that function hitme() within the call_from_outside() function between the <fx:Script> tags?
The reason why I'm doing this is because I have some flash swfs that I load into another swf file and I can access the top level public functions of those flash swfs, however the top level of the flash builder/flex swfs is the main mxml file not my fake as3 class root. Of course I should think there is a way for me to access the as3 class methods of the mxml component but for keeping things with the same structure, I can bypass having to modify my loader scripts. Anyone have an ideas?
(Please note that I changed your closing tag below. It will cause headaches if you omit that).
It looks like all you need to do is add an ID to your custom class:
<com id="myCustomClass">
</com:MyAS3DocClass>
And then you can simply access that value as a variable name inside the script tag:
public function call_from_outside():void
{
myCustomClass.hitme();
//other stuff
}
AND HERE'S WHY!
When you assign an ID to a tag in an MXML file, it is the same thing as adding public var <your-variable-name-here>:<tag-class> to an AS file (of course that's done by the compiler, so you shouldn't need to care). Once you assign an ID to MyAS3DocClass, it is instantly a publicly accessible variable. Once it is a publicly accessible variable, it can be used in public, protected, internal, namespace, and private functions!
If you don't like this idea and your custom class is a DisplayObject, you can also do this:
<com:MyAS3DocClass name="myCustomClass" />
then, in the script tag:
public function call_from_outside():void
{
MyAS3DocClass(getChildByName("myCustomClass")).hitme();
//other stuff
}

Can I make my Flex entry-point MXML subclass a custom AS3 class

With MXML components, I've seen a pattern used where you have an AS3 class, then the MXML subclasses it, to have a separation between view/code (anonymized from real code):
package com.john
{
public class MyComponent extends Canvas
{
...
}
}
<?xml version="1.0" encoding="utf-8"?>
<logic:MyComponent xmlns:logic="com.john.*"
xmlns:mx="http://www.adobe.com/2006/mxml">
...
</logic:MyComponent>
At least I think the MXML component is subclassing the AS3 class?
Anyway is it possible/advised to do this with my main MXML application file, so I can put manager instances and things in the AS3 MyApp class, which is subclassed by Main.MXML?
Real/pseudo code examples are most welcome.
It should be possible, looks like you just need to have your com.john.MyComponent base class extend spark.components.Application or mx.core.Application.
But whether it's advised or not, I don't see the benefits unless you are planning to reuse that base class somehow. If it's a heavy app class or just despise mxml, refactoring out implementation code to a startup command and composing any child views in another container will really lighten the app class. I'd even prefer the app class composing your current MyComponent over converting it to a base application class and extending.