locked
How to navigate to a new page from within a OnFrameNavigated handler

    Question

  • I am porting a Windows Phone 8 app to Windows Store 8.1 and I am having some trouble with navigating to a new page when Frame.Navigate(...) is called from within a OnFrameNavigated handler.

    The long story:

    The App manages different "Media" objects like Books or Films. To edit the properties (title, author, etc.) of such an element the WP uses a custom "MediaEditor" control that was inspired by the DatePicker from the WP ToolKit:

    Instead of manually navigating to an Editor/Picker page the Editor/Picker is capsuled in its own class. This class hooks up to the ApplicationFrame and handles Navigation to the Editor/Picker page on its own. When the ApplicationFrame navigates back to the page/content that was visible before showing the Editor/Picker the result can be processed, e.g. fire an event with the picked date.

    There is one difference in my MediaEditor compared to the DatePicker: If the MediaItem that is currently edited is related to another MediaItem (e.g. Movie A is the film version of Book A) the editing of this item can directly been started from within the MediaEditor:

    • call mediaEditor.Edit(MovieA) --> MediaEditor for MovieA is displayed
    • Select to Edit BookA from within MediaEditor --> MediaEditor for MovieA is closed and MediaEditor for BoolB is displayed

    This is done by calling Edit(BookA) from within OnFrameNavigated. Thus the complete Navigation is:

    • call mediaEditor.Edit(MovieA) --> Frame.Navigate(typeof(MediaEditorPage), MovieA)
    • Select to Edit BookA --> Frame.GoBack()
    • Detect that BookA should be edited in OnFrameNavigated --> Frame.Navigate(typeof(MediaEditorPage), BookA)

    While this works on Windows Phone this does not work on Win 8.1. Frame.Navigate(typeof(MediaEditorPage), BookA) is simply ignored. There is no OnNavigationFailed, no console output, nothing. The App navigates back to the first page (the one that original called mediaEditor.Edit(MovieA)) and nothing else happens.

    What exactly is the problem here?

    MediaEditor mediaEditor = new MediaEditor();
    mediaEditor.Edit(bookItem);
    
    
    public class MediaEditor {
        private Frame applicationFrame;
        private object frameContentWhenOpened;
    
    
        public void Edit(MediaItem item) {
            applicationFrame = Window.Current.Content as Frame;
    
    
            if (applicationFrame != null) {
                frameContentWhenOpened = applicationFrame.Content;
    
                applicationFrame.Navigated += OnFrameNavigated;
                applicationFrame.NavigationFailed += OnNavigationFailed;
    
                applicationFrame.Navigate(typeof(MediaEditorPage), item);
            }
        }
    
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e) {
            System.Diagnostics.Debug.WriteLine(e);
        }
    
    
        MediaEditorPage editorPage;
        void OnFrameNavigated(object sender, NavigationFailedEventArgs e) {
            if (e.Content == frameContentWhenOpened) {
                applicationFrame.Navigated -= OnFrameNavigated;
                applicationFrame.NavigationFailed -= OnNavigationFailed;
    
                applicationFrame = null;
                frameContentWhenOpened = null;
    
                if (editorPage != null) {
                    if (editorPage.EditOtherItem)
                       // Directly start editing another Item
                       Edit(editorPage.OtherItem);
                    else
                       // Finish editing, fire Events, etc
                }
            } else {
                editorPage = e.Content as MediaEditorPage ;
            }
        }
    
    }

    Tuesday, February 25, 2014 8:30 AM

Answers

  • Thx for the explanation, yes there is error while navigation.

    You have a GoBack() in the Button_Click_1 event, this means when user click the button, current page will navigate back to the pervious one, however in your case you would navigate the current DialogPage to another new DialogPage, GoBack method is the suitable one here for your scenario.

    Besides, Frame.Navigated event only occurs when the content that is being navigated to has been found, if we remove the GoBack() method, you would have no chance to navigate the page.

    Here I have two workarounds for you:

    The first one is quite easy, re-write the Button_Click_1 method by following code, by this you may got a huge workload for your project if there are too many DialogPage to show.

            private void Button_Click_1(object sender, RoutedEventArgs e) {
                OpenNewDialog = true;
                Dialog dialog = new Dialog();
                dialog.Show("asdsadasdasdasda");
                //GoBack();   
            }

    The second one is more complicated, register an event listener for Frame.Loaded event and write your logical here instead of in OnFrameNavigated method (for instance check the Frame navigation history or use e.OriginalSource ). And when you click the button, use Frame.Navigate(typeof(DialogPage)) instead GoBack(), otherwise you cannot navigate to a correct place.

    applicationFrame.Loaded += applicationFrame_Loaded;
    Hope this helps.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.


    Wednesday, March 12, 2014 9:28 AM
    Moderator

All replies

  • Hi Agenor,

    Quite a long story. Hard to understand the whole scenario, if you could upload a reproducible demo to skydrive, it would be more easier for us to understand the situation and to provide suggestions.

    For debugging the app, I would suggest you to put a breakpoint on your navigation line to see if the code has been executed. I saw you create a MediaEditorPage element, but I do not see you initialize it, may I understand as while the first time your OnFrameNavigated event fires, the editorPage is null.

    Not quite sure if I misunderstand something, but if you explain more, that would be nice.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.


    Wednesday, February 26, 2014 5:58 AM
    Moderator
  • Hi,

    thank you for your answer. I created a demo project and placed on my OneDrive:

    http://1drv.ms/1cqK3N2

    - Run the App and click on "Show Dialog". The DialogPage is displayed.
    - Click on "Close" to close the dialog.
    - App returns to MainPage
    ==> OK

    - Run the App and click on "Show Dialog". The DialogPage is displayed.
    - Click on "Open new dialog"
    - App returns to MainPage
    ==> ERROR (Dialog with other content should be displayed)

    Tuesday, March 4, 2014 2:37 PM
  • Sorry, nothing wrong in my environment, everything just works fine without any error as expected.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.


    Monday, March 10, 2014 8:49 AM
    Moderator
  • You are running the demo under Win 8.1. and the apps does not return to the main page when clicking on "Open new dialog" within the first dialog?

    Please not that "ERROR" does not mean that there is something like a crash or an error message but just that the app does not behaves as expected (returns to main page instead of showing new dialog).

    Wednesday, March 12, 2014 8:45 AM
  • Thx for the explanation, yes there is error while navigation.

    You have a GoBack() in the Button_Click_1 event, this means when user click the button, current page will navigate back to the pervious one, however in your case you would navigate the current DialogPage to another new DialogPage, GoBack method is the suitable one here for your scenario.

    Besides, Frame.Navigated event only occurs when the content that is being navigated to has been found, if we remove the GoBack() method, you would have no chance to navigate the page.

    Here I have two workarounds for you:

    The first one is quite easy, re-write the Button_Click_1 method by following code, by this you may got a huge workload for your project if there are too many DialogPage to show.

            private void Button_Click_1(object sender, RoutedEventArgs e) {
                OpenNewDialog = true;
                Dialog dialog = new Dialog();
                dialog.Show("asdsadasdasdasda");
                //GoBack();   
            }

    The second one is more complicated, register an event listener for Frame.Loaded event and write your logical here instead of in OnFrameNavigated method (for instance check the Frame navigation history or use e.OriginalSource ). And when you click the button, use Frame.Navigate(typeof(DialogPage)) instead GoBack(), otherwise you cannot navigate to a correct place.

    applicationFrame.Loaded += applicationFrame_Loaded;
    Hope this helps.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.


    Wednesday, March 12, 2014 9:28 AM
    Moderator
  • Most likely the navigation isn't finished before you're attempting to start a new navigation (in your OnNavigatedTo... Edit... call)

    Try adding this:

    Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
    () => this.Frame.Navigate(typeof(MediaEditorPage)));

    Instead of just Frame.Navigate(...

    It will queue the navigation for when the system is idle from the last navigation and ready to navigate again.


    Darin R.

    Wednesday, March 12, 2014 5:06 PM