Multiple windows

JeffW.'s Avatar

JeffW.

12 Jun, 2013 04:31 PM

hi,

I am going to work on an AIR app built in RL 1 and I need to work with multiple windows that share models and services.
there are a couple of threads here that suggest that this would be made easier in RL 2, like here:
http://knowledge.robotlegs.org/discussions/questions/578-multiple-windows-in-air-application

Is this the case? And if so, does that work with multiple contexts or smt like simpler mediation of the context views in the windows?
And, I know this is hard to say, but would it be worthwhile to migrate from RL 1 to RL 2 for this - not so complicated - project?

Is there any info somewhere on this specific topic? And is there something like a migration guide for converting a RL1 to a RL2 project?

thanks!

Jeff.

  1. Support Staff 1 Posted by Ondina D.F. on 13 Jun, 2013 09:34 AM

    Ondina D.F.'s Avatar

    Hi Jeff,

    Your post got stuck in the spam queue for some weird reason.

    Yes, it’s easier to work with popups and AIR Windows in rl2.
    The ViewManager takes care of everything ;)

    Mapping:

    mediatorMap.map(SomeWindowView).toMediator(SomeWindowMediator);
    

    Oppening the Window:

        var someWindow:SomeWindowView = new SomeWindowView();
    
        viewManager.addContainer(someWindow);
    
        someWindow.open();
    

    Closing and removing the Window

    SomeWindow.mxml

    protected function window1_closeHandler(event:Event):void
    {
        this.owner.removeChild(this);
        //the owner is WindowedSystemManager
    }
    

    SomeWindowMediator

    override public function destroy():void
    {
        viewManager.removeContainer(view);
    
        super.destroy();
    }
    

    If it’s not clear, let me know.

    See Shaun’s answer regarding the ViewManager:
    http://knowledge.robotlegs.org/discussions/robotlegs-2/553-viewmana...

    And, I know this is hard to say, but would it be worthwhile to migrate from RL 1 to RL 2 for this - not so complicated - project?

    Yes, it’s definitely worthwhile to migrate from rl1 to rl2!! :)

    Is there any info somewhere on this specific topic? And is there something like a migration guide for converting a RL1 to a RL2 project?

    There is no ‘real’ tutorial yet. The rl2 documentation is on github:
    https://github.com/robotlegs/robotlegs-framework/tree/master/src/ro...

    Also, see my answer in the linked thread:
    http://knowledge.robotlegs.org/discussions/questions/2209-mediator-...

    Does this help?

    Ondina

  2. 2 Posted by JeffW. on 14 Jun, 2013 11:33 AM

    JeffW.'s Avatar

    Thanks, Ondina, great info, I'll look into RL2 then ;)

  3. Support Staff 3 Posted by Ondina D.F. on 14 Jun, 2013 12:16 PM

    Ondina D.F.'s Avatar

    Cool:)

  4. Ondina D.F. closed this discussion on 14 Jun, 2013 12:16 PM.

  5. JeffW. re-opened this discussion on 14 Jun, 2013 02:01 PM

  6. 4 Posted by JeffW. on 14 Jun, 2013 02:01 PM

    JeffW.'s Avatar

    I am trying to simply open a new NativeWindow in an AIR project and I wonder what sort of object the SomeWindowView is in your example above. Is that a regular view based on Sprite, which an open() method, or is that method somehow built in in RL?
    And how does working with the ViewManager work wit NativeWindow?

    In other words, how does your example code relate to smt like the following code:

    var viewB:ViewB = new ViewB();
    var nw =new NativeWindow(new NativeWindowInitOptions);
    nw.width=1024;
    nw.height=576;
    nw.stage.addChild(viewB);
    nw.stage.scaleMode = StageScaleMode.NO_SCALE;
    nw.activate();
    

    And are there by any chance any additional features built in to work with native windows, like setting their positions or going fullscreen?

    I assume I need to map the ViewManager before I can use/inject it, is this a good way to do that?
    context.injector.map(ViewManager).asSingleton();

    thanks,
    Jeff.

  7. Support Staff 5 Posted by Ondina D.F. on 14 Jun, 2013 02:32 PM

    Ondina D.F.'s Avatar

    SomeWindowView is a spark.components.Window (The Window is a top-level container for additional windows in an AIR desktop application.) in my example.

    I haven’t tried rl2 with a NativeWindow yet. I have an old rl1 project, where I used a NativeWidow with the modular utility. I’ll have to try it out with rl2 too and report back over the weekend, if that’s ok with you :)

    I assume I need to map the ViewManager before I can use/inject it, is this a good way to do that? 'context.injector.map(ViewManager).asSingleton();'

    You don’t need to map the ViewManager. If the ViewManagerExtension has been installed, you’ll have access to the ViewManager wherever you inject it:
    [Inject] public var viewManager:IViewManager;

    Since the ViewManagerExtension is included in the MVCSBundle, you don’t have to install it separately.

    ViewManagerExtension
    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

    MVCSBundle
    https://github.com/robotlegs/robotlegs-framework/blob/master/src/ro...

  8. 6 Posted by JeffW. on 14 Jun, 2013 03:02 PM

    JeffW.'s Avatar

    okay, I can now access ViewManager without mapping it. Thanks for looking into it, no hurry, I will also report my findings. By the way, I'm working in a pure as3 project, no flex.

    thanks, also for your fast replies :)
    Jeff.

  9. 7 Posted by JeffW. on 14 Jun, 2013 03:09 PM

    JeffW.'s Avatar

    Just to clarify: I'm curious about RL2 and the possible benefits of this ViewManager, because I want to share data among the initial native window and a new native window. Both windows show part of a game, with some shared logic and some 'window-specific' logic if that makes any sense. From what I read ViewManager - or RL2 in general - eases the process of mediation without having to use multiple contexts, but I don't see yet how exactly.

  10. Support Staff 8 Posted by Ondina D.F. on 14 Jun, 2013 03:21 PM

    Ondina D.F.'s Avatar

    In rl1 I used this script:
    http://www.ben-morris.com/howto-add-flex-mx-controls-to-a-nativewin...

    NativeContentView is just a ‚normal’ display object, in my case a Group.

    I’ve mapped NativeContentView to NativeContentMediator.

    var nativeWindow:ExtendedNativeWindow;
    //* Set up the NativeWindow options
    var options:NativeWindowInitOptions=new NativeWindowInitOptions();
    
    //* Create the NativeWindow
    nativeWindow=new ExtendedNativeWindow(options);
    
    //* Set the height, width and position
    nativeWindow.width=400;
    nativeWindow.height=300;
    nativeWindow.x=(Screen.mainScreen.bounds.width - 400) / 2;
    nativeWindow.y=(Screen.mainScreen.bounds.height - 300) / 2;
    nativeWindow.stage.scaleMode=StageScaleMode.NO_SCALE;
    nativeWindow.stage.align=StageAlign.TOP_LEFT;
    
    //* Create an instance of the content for the NativeWindow
    var content:NativeContentView=new NativeContentView();
    
    //* Pass the content into the native window
    nativeWindow.addChildControls(content);
    
    //here you could let the ViewManager add the content, but I haven’t tried it yet!!!
    viewManager.addContainer(content);
    
    //* Activate the window
    nativeWindow.activate();
    

    I’m running out of time for today, so to be continued (including answering your last question about the ViewManager) in the next days :)

    See ya

  11. 9 Posted by JeffW. on 14 Jun, 2013 05:17 PM

    JeffW.'s Avatar

    Well, I seem to have got smt working where I can open a new native window using the view manager. I simply map the view in the config class:

    mediatorMap.map(ViewA).toMediator(ViewAMediator);
    

    and open a native window in a command where I also add the view to the view manager, which makes it possible to dispatch (and listen for) signals through the mediator. Without adding it to the view manager no working signals.

    var viewA:ViewA = new ViewA();
                
    var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    options.renderMode = NativeWindowRenderMode.DIRECT;
    var nw:NativeWindow =new NativeWindow(options);
    nw.width=1024;
    nw.height=576;
    viewManager.addContainer(viewA);
    //          trace(viewManager.containers[1] );//outputs View A
    nw.stage.addChild(viewA );
    nw.stage.scaleMode = StageScaleMode.NO_SCALE;
    //          nw.stage.displayState = StageDisplayState.FULL_SCREEN;
    nw.activate();
    

    Btw, this only works when I add the view to the view manager before I add it to
    the stage of the native window.

  12. Support Staff 10 Posted by Ondina D.F. on 15 Jun, 2013 06:50 AM

    Ondina D.F.'s Avatar

    Hey Jeff,

    You’re right. The view has to be added to the viewManager before it gets added to the stage, otherwise the viewManager cannot know when the view is added to the stage…
    I was in a hurry when I pasted the rl1 code, and I just placed the line for viewManager in there without thinking too much about it. Sorry for that.

    Same rule applies to popups:

    //1 instantiate a title window
    var titleWindowInstance:SomePopUpView = new SomePopUpView(); 
    //2 add the TitleWindow to the viewManager
    viewManager.addContainer(titleWindowInstance);
    //3 then add it to the popupmanager
    PopUpManager.addPopUp(titleWindowInstance, FlexGlobals.topLevelApplication as DisplayObject);
    

    I haven’t had time to try it out yet, but I wonder how your code works. In my example from rl1 I used the ExtendedNativeWindow, where WindowedSystemManager is the one adding the component to the window.

    Adobe: You cannot add Flex components directly to the display list of a NativeWindow instance. Instead, use the Flex mx:WindowedApplication and mx:Window components to create your windows and add the other Flex components as children of those objects. You can add Flex-based SWF content directly to a NativeWindow window as long as the SWF file is loaded into its own application domain and is application content.

    So, either you use something similar to the ExtendedNativeWindow, or you simply do this:

    var viewA:ViewA = new ViewA();
    var options:NativeWindowInitOptions = new NativeWindowInitOptions();
    options.renderMode = NativeWindowRenderMode.DIRECT;
    
    viewManager.addContainer(viewA);//1
    
    var systemManager:WindowedSystemManager = new WindowedSystemManager(viewA);//2
    
    nw.stage.addChild(systemManager );//3
    
    nw.activate();//4
    

    Just to clarify: I'm curious about RL2 and the possible benefits of this ViewManager, because I want to share data among the initial native window and a new native window. Both windows show part of a game, with some shared logic and some 'window-specific' logic if that makes any sense.

    We’ll talk about this later today or tomorrow. Now I’m going to go out to enjoy the sun:)

    Ondina

  13. 11 Posted by JeffW. on 15 Jun, 2013 07:47 AM

    JeffW.'s Avatar

    hi Ondina,

    I'm working in a pure as3 project so I'm not using the WindowedSystemManager nor do I want to add flex components to the new window, just as3 content. So I simply map my view to a mediator, create and open a new native window, add the content (a sprite view) to its stage and before that also to the view manager.

    Adding it to the view manager makes it possible to make use of the view-mediator mapping. I can dispatch events(signals) and listen for them in both directions (app < > new window), so I'm quite happy with that.

    Closing the window also works albeit in a way that may feel a bit like a workaround. I save the instance of the new window in a model, so that I later can access it from any other command and call smt like

    [Inject]
    public var wnModel:WindowModel;
    
    wnModel.myWindow.close();
    
    So I can indeed establish communication between the initial and new window and hopefully it will also work when I want to switch between views in the new window, smt I will try next, by adding other views to the manager.

    Enjoy the sun!

  14. Support Staff 12 Posted by Ondina D.F. on 15 Jun, 2013 05:35 PM

    Ondina D.F.'s Avatar

    Oh, yes, you told me already in one of your posts that your project is a pure as3 one! I totally forgot about that.

    I also forgot to tell you that you have to remove the view from the viewManager when it’s removed from stage.

    viewManager.removeContainer(view);

    Thanks for sharing your findings.
    I hope to get more time tomorrow to play around with the NativeWindow in rl2. I’m curious how it behaves in terms of garbage collection in a Flex and a pure as3 project. Is your example working fine? Does ViewA get gc-ed?

  15. Support Staff 13 Posted by Ondina D.F. on 16 Jun, 2013 05:57 PM

    Ondina D.F.'s Avatar

    Here, my findings:

    NativeWindow in a pure as3 project behaves as expected.
    As you mentioned, it is possible to add a view (extending Sprite) to the stage of a NativeWindow. The view gets gc-ed after closing the window.

    The following is probably not interesting to you, but since there are also Flex users who might read this thread in the future, I thought it might be worth sharing my findings:

    Adding Flex components to a NativeWindow is a pain in the…code.
    It’s easy to add a component to the native window using the WindowedSystemManager, as previously mentioned in my posts, but the view doesn’t get gc-ed after closing the window. And that’s because there is kind of circular reference between View and WindowedSystemManager that keeps the view in memory. I’ve been trying several things to solve this, but to no avail. My brain hurts already… so, I’m giving up.

    My suggestion for Flex users: instead of a NativeWindow use a spark.Window, which works just fine, at least in my experience.

    So, Jeff, if you think your questions have been answered, you can close the discussion.

    Ondina

  16. 14 Posted by JeffW. on 17 Jun, 2013 07:01 AM

    JeffW.'s Avatar

    hi Ondina,

    thanks for testing, I also tested some more:
    Adding multiple views to a new native window that all have their own mediator, this works fine
    Adding child (nested) views to a view added to a new native window, with their own mediators, which also works fine.

    I have one question though. The first test works when I add the views at the same time, for instance in a startup command. I map the views and mediators in my config class. But when I try to add a view later, for instance in another command, the view is being added but there is no mediation. Do I need to manually mediate that view? And if so, how do i do that in RL2 (not even sure about RL1, never did that)? A code snippet would be great,

    thanks,
    Jeff.

  17. Support Staff 15 Posted by Ondina D.F. on 17 Jun, 2013 09:21 AM

    Ondina D.F.'s Avatar

    Hi Jeff,

    I just tried to add a second view to the nw in a pure as3 project. You need to tell the viewManager about it, so you’ll have to inject the viewManager into the command that is adding the view:

    var anotherView:AnotherView = new AnotherView();
    viewManager.addContainer(anotherView);
    nw.stage.addChild(anotherView );
    

    AnotherMediator will be created, if you mapped AnotherView to it.

    The problem is, AnotherView doesn’t get removed from the NativeWindow after closing it, therefore its mediator doesn’t get destroyed. So, both, AnotherView and AnotherMediator, aren’t eligible for gc.

    I’d need more time to investigate this( in a Flex project as well )
    I’ll let you know how it goes.

    Ondina

  18. 16 Posted by JeffW. on 17 Jun, 2013 09:49 AM

    JeffW.'s Avatar

    You are right, mediaton does get initialized, I had a typo in my code. And I see the same thing with the other view still existing. I seem to be able to remove it from the view manager, but it is still on that window's stage. But this may be an AIR problem and not so much a RL issue?

  19. Support Staff 17 Posted by Ondina D.F. on 17 Jun, 2013 10:34 AM

    Ondina D.F.'s Avatar

    But this may be an AIR problem

    Yes, that's what I think too.

  20. Support Staff 18 Posted by Ondina D.F. on 17 Jun, 2013 11:17 AM

    Ondina D.F.'s Avatar

    I’ve tested it with a spark.Window, and it works fine. I can add an additional view to it, and after closing the Window, both views and their mediators get gc-ed.
    I added an event handler for the CLOSE event in the Window, where I removed all its children and I also removed the Window from its owner, which is the WindowedSystemManager.
    I’ll post the code later on, but that doesn’t help you very much, because you’re using the NativeWindow. So, Flex or no Flex, it seems the NativeWindow is the problem.

    I don’t know yet if there is a way to remove the children from the NativeWindow. When I close the nw, it seems there is only one child, and that is the first one added, even though after I add the second child, the nw has indeed 2 children…weird. If you find a solution, I’d be curious to know about it, and it would help others as well.

  21. Support Staff 19 Posted by Ondina D.F. on 17 Jun, 2013 11:53 AM

    Ondina D.F.'s Avatar

    Correction: It works with NativeWindow, too. When you remove the children from the nw, you should use a while loop, not a for loop.

  22. Support Staff 20 Posted by Ondina D.F. on 17 Jun, 2013 12:25 PM

    Ondina D.F.'s Avatar

    Code snippets for pure as3 NativeWindow:

    In config:

    mediatorMap
    .map(SomeView)
    .toMediator(SomeMediator);
    
    mediatorMap
    .map(AnotherView)
    .toMediator(AnotherMediator);
    

    Open the window and add SomeView:

    protected function onOpenWindow():void
    {
        var someView:SomeView = new SomeView();
    
        var options:NativeWindowInitOptions = new NativeWindowInitOptions();
        options.renderMode = NativeWindowRenderMode.DIRECT;
        nw = new NativeWindow(options);
        nw.addEventListener(Event.CLOSING, onWindowClosing);
        nw.width = 500;
        nw.height = 500;
    
        viewManager.addContainer(someView);
    
        nw.stage.addChild(someView);
    
        nw.stage.scaleMode = StageScaleMode.NO_SCALE;
        nw.activate();
    }
    

    Add another view:

    protected function onAddViewToNW():void
    {
        var anotherView:AnotherView = new AnotherView();
    
        viewManager.addContainer(anotherView);
    
        nw.stage.addChild(anotherView );
    }
    

    Removing Window’s children:

    protected function onWindowClosing(event:Event):void
    {
        while(nw.stage.numChildren>0)
        {
            nw.stage.removeChildAt(0);
        }
    }
    

    SomeView on removed from stage (same for AnotherView)

    protected function onRemoveFromstage(event:Event):void
    {
        //remove all event listeners
        removeEventListener(Event.ADDED_TO_STAGE, onAddedTostage);
        removeEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromstage);
        //remove children
        while(nw.stage.numChildren>0)
        {
            nw.stage.removeChildAt(0);
        }
    }
    

    SomeMediator (same for AnotherMediator):

    override public function destroy():void
    {
        viewManager.removeContainer(view);
        super.destroy();
    }
    
  23. 21 Posted by JeffW. on 17 Jun, 2013 12:30 PM

    JeffW.'s Avatar

    Yes, I got it working too. Great, now I can have multiple windows partly sharing the same data in only one context. I leave it to you to close this thread...

  24. Support Staff 22 Posted by Ondina D.F. on 17 Jun, 2013 12:51 PM

    Ondina D.F.'s Avatar

    Yes, I got it working too. Great, now I can have multiple windows partly sharing the same data in only one context. I leave it to you to close this thread...

    Awesome :)

    Flex usage with spark Window

    Mappings as above.

    Opening a Window:

    private var someWindow:SomeWindowView;
    
    private function onOpenWindow(event:ShellNavigatorEvent):void
    {
        someWindow = new SomeWindowView();          
        viewManager.addContainer(someWindow);
    
        someWindow.addElement(new SomeView());
        someWindow.addEventListener(Event.CLOSING, onWindowClose);
        someWindow.width = 500;
        someWindow.height = 500;
        someWindow.open();
    }
    

    Add another view to the opened window:

    private function onAddViewToWindow(event:ShellNavigatorEvent):void
    {
        someWindow.addElement(new AnotherView());
    }
    

    Closing handler:

    protected function onWindowClose(event:Event):void
    {
        someWindow=null;
    }
    

    SomeWindowView on closing

    protected function window1_closeHandler(event:Event):void
    {
        //remove all event listeners
        removeEventListener(Event.CLOSE, window1_closeHandler);
    
        removeAllElements();
    
        this.owner.removeChild(this);//owner == WindowedSystemManager
    }
    

    SomeView and AnotherView

    protected function onRemovedFromoStage(event:Event):void
    {
        //remove all event listeners
        removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromoStage);
        removeAllElements();
    }
    

    SomeMediator and AnotherMediator

    override public function destroy():void
    {
        viewManager.removeContainer(view);
        super.destroy();
    }
    

    Now I’m done ;) Discussion closed.

  25. Ondina D.F. closed this discussion on 17 Jun, 2013 12:51 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac