How to use form, after it is "fully" added to stage?

maciekrei's Avatar

maciekrei

21 Nov, 2011 10:55 AM

Hello,
I'm making simple formula with few forms. When I try to change between forms, theres one form view in which I would perform some actions after it is fully drawed and placed on stage. Unfortunently, when I handle addedToStage or creationComplete events and then dispatch some events to views mediator, it doesnt responde (like it wouldnt have time to add listeners on register). On the other side, when I just try to perform some actions in mediators onRegister() function, it seems, that it is too soon for form to occure on the stage (in my case there is still previuos form visible).

What can do to solve this? For now I tried desperate tactics, like adding timer, waiting 50ms and then performing neccessary actions. I want to change it, because it looks awful.

  1. 1 Posted by Stray on 21 Nov, 2011 11:01 AM

    Stray's Avatar

    Hi there,

    if this form extends UIComponent, and dispatches creationComplete, then Robotlegs waits for this event before the Mediator runs onRegister.

    What kind of actions are you performing? Are they related to data, or more like skinning?

    Stray

  2. 2 Posted by maciekrei on 21 Nov, 2011 11:21 AM

    maciekrei's Avatar

    I'm copying or moving desktop files and I want to show progress on the next form, but form occurs too late - it shows in the half of the process or after it ends.

    And yes, it's uicomponent (spark.components.form).

  3. Support Staff 3 Posted by Ondina D.F. on 21 Nov, 2011 02:24 PM

    Ondina D.F.'s Avatar

    Hi,

    Help us understand your issue by answering a few questions :)

    1. In an AIR application you have 2 Views: I’ll call them FileManagerView and ProgressIndicatorView. (I can’t come up with better names right now)
      Inside your FileManagerView you are performing actions like File.copyTo(),File.moveTo()or maybe you are using a FileStream object to read and write files.
      Your ProgressIndicatorView is supposed to visualize the progress of the tasks occuring in FileManagerView
      Right?

    2. How is the not functioning View(ProgressIndicatorView) added to the display list? Are you using states? Are you using a ViewStack? Are you adding it through actionscript?

    3. When are you adding the View to the display list? Before or after the FileMangerView has been added to the display list?
    4. Are you disptching an event from the FileMangerView, that its mediator would re-dispatch and the ProgressIndicatorView’s mediator would listen to it?
    5. Are the FileStream operations synchronous or asynchronous?

    So, in case I missed the point completely more details about your specific use case are needed in order to find the culprit :)

    Ondina

  4. 4 Posted by maciekrei on 21 Nov, 2011 05:20 PM

    maciekrei's Avatar
    1. It works this way:
      1.1. I have MainView, in which I change curent visible form (lets use your namspace, FileManagerView and ProgressIndicatorView). 1.2 In FileManagerView I gather information, like path were the files have to be copied etc. 1.3. Then I click next button, which dispatches event. MainView mediator handles this event and FileManagerView is removed and ProgressIndicatorView is added as a child of MainView. 1.4 Then I dispatch an event, which is handled by command. This command executes service, that is responsible for movying and copying files. 1.5 First part of file operations are synchronous, but most of them are asynchronous. 1.6 When single file is copied or moved, service dispatches event, that is handled by ProgrssIndicatorView mediator. Mediator updates its views data, showed by views progress bar (simple progess of copied files).

    2. When I click next button and wait for ProgressIndicatorView to occur, button freezes instead with FileManagerView still on board. Then ProgressIndicatorView shows, but most of the process on the progress bar is over or it is completly finished.

    I guess, I answered points 3, 4 and 5 in points 1.3-1.5.

    As I think now, my problem can be those synchronous operations, that freeze whole thing. Although, I need to create some files before another and making this with chain-events, which wait one for another like 6 times would too messy.

    All in all, I hope, I clarified my sytuation, if not, I can still answer more questions. I just whant to find a nice, clear way to get rid of that ugly timer :)

  5. Support Staff 5 Posted by Ondina D.F. on 21 Nov, 2011 06:26 PM

    Ondina D.F.'s Avatar

    ok. next round of questions:)

    “Then I click next button, which dispatches event. MainView mediator handles this event and FileManagerView is removed and ProgressIndicatorView is added as a child of MainView.”
    “When I click next button and wait for ProgressIndicatorView to occur, button freezes instead with FileManagerView still on board. Then ProgressIndicatorView shows, but most of the process on the progress bar is over or it is completly finished.“

    If you comment out the mapping for ProgressIndicatorView so it has no mediator, and let MainView add it as you described, is this “freezing” still occurring?

    “Then I dispatch and event, which is handled by command. This command executes service, that is responsible for movying and copying files.”

    Who is dispatching the event that triggers the command?

    Is ProgressIndicatorView already added to the display list by the time the service dispatches an event?
    I suspect that’s the problem: race condition. You are probably dispatching an event with the name of the file as a payload from FileManagerView’s Mediator to trigger the command and make the service call. The service starts doing its job, dispatches an event, none hears it, then MainView’s mediator receives the event from NextButton and adds the ProgressIndicatorView to the display list. At some point in time ProgressIndicatorView’s Mediator is able to listen to the events dispatched by the service and passes the data to the view from this moment on, therefore incomplete.

    One solution to this issue could be:

    FileManagerView’s Mediator dispatches an event with the file name as payload. The event triggers a command that sets the filename in a FileManagerModel.
    When the user clicks the NextButton the MainView’s Mediator adds ProgressIndicatorView to the stage. The ProgressIndicatorView’s mediator onRegister() registers an event listener for the event that will be dispatched by the service and then dispatches an event to trigger a command that will first read the filename set in FileManagerModel and call the service with it as an argument.

    Now, there is another solution as well, but I’m not sure you want it. You’d have a FileManagerView containing the Form and the ProgressIndicatorView, which will be hidden at first. Nevertheless its mediator will be created and will be able to listen to the event dispatched by the service. The user fills in the file name, clicks next, FileManagerView’s mediator dispatches the event with the filename as payload, triggers the command, calls the service. The service dispatches an event and ProgressIndicatorView’s Mediator in its onDataReceived() method sets the ProgressIndicatorView to visible and passes the data to the progressbar.

    I wrote this down in a hurry, so I’m not sure if it’s clear enough.

  6. Support Staff 6 Posted by Ondina D.F. on 21 Nov, 2011 06:48 PM

    Ondina D.F.'s Avatar

    If the way you’re adding the ProgressIndicatorView to the display list isn't an issue and there are no race conditions, then you should also look at discussions about commands detain() and release() on this forum.
    Search for detain(), chaining commands.

  7. 7 Posted by maciekrei on 23 Nov, 2011 09:11 AM

    maciekrei's Avatar
    1. "If you comment out the mapping for ProgressIndicatorView so it has no mediator, and let MainView add it as you described, is this “freezing” still occurring?"

    No, form appears as it should.

    1. "Who is dispatching the event that triggers the command?"

    ProgressIndicatorView mediator dispatches it (currently 50ms after registered)

    1. "Is ProgressIndicatorView already added to the display list by the time the service dispatches an event?"

    I guess, the mediators onRegister function triggers after child is added to stage, so I'ld say yes.

    1. "I suspect that’s the problem: race condition. You are probably dispatching an event with the name of the file as a payload from FileManagerView’s Mediator to trigger the command and make the service call. The service starts doing its job, dispatches an event, none hears it, then MainView’s mediator receives the event from NextButton and adds the ProgressIndicatorView to the display list. At some point in time ProgressIndicatorView’s Mediator is able to listen to the events dispatched by the service and passes the data to the view from this moment on, therefore incomplete.

    One solution to this issue could be:

    FileManagerView’s Mediator dispatches an event with the file name as payload. The event triggers a command that sets the filename in a FileManagerModel.
    When the user clicks the NextButton the MainView’s Mediator adds ProgressIndicatorView to the stage. The ProgressIndicatorView’s mediator onRegister() registers an event listener for the event that will be dispatched by the service and then dispatches an event to trigger a command that will first read the filename set in FileManagerModel and call the service with it as an argument."

    I'm not sure if this is race condition. If I state correctly in previous answer, the onRegister function in ProgressIndicatorViewMediator is triggered after ProgressIndicatorView is added to stage. So theoretically form should be added first and then command should be executed.

    1. "Now, there is another solution as well, but I’m not sure you want it. You’d have a FileManagerView containing the Form and the ProgressIndicatorView, which will be hidden at first. Nevertheless its mediator will be created and will be able to listen to the event dispatched by the service. The user fills in the file name, clicks next, FileManagerView’s mediator dispatches the event with the filename as payload, triggers the command, calls the service. The service dispatches an event and ProgressIndicatorView’s Mediator in its onDataReceived() method sets the ProgressIndicatorView to visible and passes the data to the progressbar."

    I guess, I havent described how my whole app works. I have MainView and 6 forms in it, which are switched one after another by Next or Back button. I have also model, which stores data from those views.

    When form dispatches some button events, which handled by its mediator, changes some local data (e.g. browse action), then model is automatically updated. If form has some textfields, there are saved in model after next or back click occurs and form is changed to next one (I could add onChange handler to every one, by it seemed too hard working).

    The case is, when FileManagerView to ProgressIndicatorView, I dont have to dispatch event that changes file location data, because its already stored in model.

    About view in view solution, well sounds like it could work, but I fear about changing whole thing so drastically. I already have Views in View. Although, if there will be no solution, I could try it.

    1. "If the way you’re adding the ProgressIndicatorView to the display list isn't an issue and there are no race conditions, then you should also look at discussions about commands detain() and release() on this forum.
      Search for detain(), chaining commands."

    Hm... but even, if command would be already initiated, I still dont know how to dispatch event from ProgressIndicatorView mediator, after its view would be fully added and showed on stage.

    (EDIT. Why I have all "1"s in numeric list, although I used 1-7? O_o)

  8. Support Staff 8 Posted by Ondina D.F. on 23 Nov, 2011 09:48 AM

    Ondina D.F.'s Avatar

    I’m willing to take a look at your code, if you’d let me see it (strip out your proprietary code and post an FXP or zip of the project ??)
    It’s quite difficult to understand what’s going on without seeing some code:
    at least a simplified version of the MainView, FileManagerView, ProgressIndicatorView and their Mediators
    What do you think?

  9. 9 Posted by maciekrei on 23 Nov, 2011 10:36 AM

    maciekrei's Avatar

    Ok, I have compressed app to needed files. FileManagerView is GenerateFormView, then you have GeneratePopupView, which checks if everything is clear, and then is launched ProgressIndicatorView as ProgressFormView (in my case).

  10. Support Staff 10 Posted by Ondina D.F. on 23 Nov, 2011 10:40 AM

    Ondina D.F.'s Avatar

    ok. I'll take a look at it and answer as soon as possible:)

  11. Support Staff 11 Posted by Ondina D.F. on 23 Nov, 2011 03:07 PM

    Ondina D.F.'s Avatar

    Wow! It wasn’t easy to understand your code;) Since it’s incomplete and a lot of classes are missing I couldn’t compile it until I commented out a lot of code. From what I could make work I saw this flow:

    1. GenerateFormView dispatches GenerateFormView.BROWSE_CLICK
    2. GenerateFormViewMediator dispatches BrowseDestinationEvent.BROWSE
    3. BrowseDesinationCommand -> LoadDestinationFolderService.browse()
    4. LoadDestinationFolderService.handleSelect -> BrowseDestinationEvent.BROWSE_RESPONSE
    5. GenerateFormViewMediator. handleBrowseResponse -> view.setBrowseInput(e.file.url);

    Then:
    1. MainMediator.handleNextClick dispatches ChangedMenuEvent.CHANGED
    2. MainMediator.handleMenuChanged -> view.changeFormView-> this.MenuForm.addElement(formViews[formNumber]);
    3. ProgressFormView is added to the display list
    4. ProgressFormViewMediator.onRegister:
    addContextListener(GenerateApplicationEvent.GENERATE_APP_RESULT, handleGenerationResult);
    addContextListener(ProgressGenerationEvent.GENERATION_PROGRESS, handleProgress);
    dispatch( new GenerateApplicationEvent(GenerateApplicationEvent.GENERATE_APP) );
    5. triggers GenerateApplicationCommand -> calls ApplicationGeneratorService.generate()
    6. and in setCurrentProgress dispatch( new ProgressGenerationEvent(ProgressGenerationEvent.GENERATION_PROGRESS, _currentProgress / progressTotal, label));
    7. ProgressFormViewMediator. handleProgress
    8. view.changeProgress(e.progress, e.label);

    Now, to make it work I added GenerateFormView to MainView through mxml.
    Then on next button click I did this:
    public function changeFormView(formNumber:int, formViews:Array):void
    { this.MenuForm.addElement(new ProgressFormView());

    I couldn’t use the views from your model, because they weren’t there.

    In ApplicationGeneratorService I used a ‘for’ loop to setCurrentProgress, which then dispatched the ProgressGenerationEvent.GENERATION_PROGRESS.
    ProgressFormView is receiving the fake data from service!

    Then I created another View and used your FormViewModel array and Main.changeFormView to add and remove views and it also worked.

    There is no need to use the Timer in the ProgressFormViewMediator’s onregister()

    I suggest you isolate the ProgressFormView, ProgressFormViewMediator, GenerateApplicationCommand and the ApplicationGeneratorService by making a separate project containing just them. If it doesn’t work as expected then I guess the ApplicationGeneratorService is the problem. If i could use your code I would try detain() and release() in the command to see if it solved the problem.

    You could also try to use the logic from your ApplicationGeneratorService in a simple ui component, i.e. without the entire framework, and set the progressGeneration.setProgress in the view and see if it works as expected.
    Another mini project could test the removing and adding of views in Main.mxml. Use traces to see what happens with the Mediators’ onRegister for all your views.

    I’m sorry for not being able to give you a better answer, but I can’t use the ApplicationGeneratorService to see how it works, because of the missing classes.

    Something I’ve noticed while looking at your code: You have BrowseDesinationCommand twice, under service and under commands! I’m surprised you don’t get any errors because of that. Maybe the command landed under the service folder when you prepared the project for me.
    There are other things that I’ve noticed about your code and package structure as well, but let’s concentrate on the ProgressFormView first:)

  12. Support Staff 12 Posted by Ondina D.F. on 23 Nov, 2011 06:17 PM

    Ondina D.F.'s Avatar

    I tried to use (partially) the logic from your ApplicationGeneratorService. launchFile():
    I created some files, then I launched an AIR app (that I had on my desktop), and it worked fine.
    Of course, as long as the launched AIR app was open the progress bar didn’t move any further. The moment I closed the app, I considered that the service has finished its job and I let it dispatch
    (GenerateApplicationEvent.GENERATE_APP_RESULT, "Success!\n\nApplication created."));

    Now, you are making lots of calls in your ApplicationGeneratorService.launchFile() in a sequential manner (creating, copying files, launching a native app)...and I can’t understand exactly what’s happening there. I suggest commenting out all the calls and then checking every call you make in your launchFile() step by step to see if there is one causing some trouble. Maybe you should rethink the logic in this launchFile() method?

    But, if after testing everything works fine in your ApplicationGeneratorService, then something else in your application must be the cause of errors. I have no idea what it could be. Since I was able to make it work (partially), it is clear that you have to isolate the different areas of functionality in your project and test them separately, at least by using the debugger or trace statements.

    Let us know how it goes.

  13. Support Staff 13 Posted by Ondina D.F. on 29 Nov, 2011 10:04 AM

    Ondina D.F.'s Avatar

    I would like to hear whether you’ve found a solution to your problem or not. What was actually causing it?
    In case you still don’t know how to solve it and my suggestions didn’t help, there may be others here who could give you advice. Don’t hesitate to ask more questions :)

    On the other hand, if you’ve resolved the issue and you are willing to talk about it, it could help others with similar problems. The purpose of this forum is to learn from each other (a shared knowledge base)
    Cheers,
    Ondina

  14. 14 Posted by maciekrei on 02 Dec, 2011 11:36 AM

    maciekrei's Avatar

    I'm sorry, that I made you wait so long for ma answer, but had pretty hard deadlines during this time.

    As I think about it now, Im also sorry for giving you just this bunch of classes. I havent got permission to give you whole code, because its app for company in which I work. Although, during compression of code, I've forgot that besides giving you classes, that have something to with the problem, they should also work after separation... Thanks, that you where so patient and made it work despite all problems.

    The cause of my "freeze" problem was nothing more, but my "createFile" functions in AppGenerationService class. If I use only asynchronous methods, everything works fine. So I reduced using synchronous functions to minimum (cause I still need some of them badly) and even if app freezes, its too short period of time, to be meaningful.

    Although, this is just some backdoor, I've still havent solved the problem fully. I thought about "detain() and release()" methods, but I still need to somehow trigger/release command a small moment after onRegister function executes in ProgressViewMediator...

  15. Support Staff 15 Posted by Ondina D.F. on 02 Dec, 2011 02:44 PM

    Ondina D.F.'s Avatar

    Hey Maciej,

    “I'm sorry, that I made you wait so long for ma answer, but had pretty hard deadlines during this time.”

    No problem:)

    ‘As I think about it now, Im also sorry for giving you just this bunch of classes. I havent got permission to give you whole code, because its app for company in which I work.’

    That’s understandable. I'm sorry I couldn't be of more help.

    ’The cause of my "freeze" problem was nothing more, but my "createFile" functions in AppGenerationService class.’

    I wish you luck in finding a better solution :) You still can refactor this part of your application at a later time.

    I'm going to close this thread, but feel free to reopen it if need be.

    Cheers,
    Ondina

  16. Ondina D.F. closed this discussion on 02 Dec, 2011 02:44 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