UWP App Can not modify navigation stack

I have a CrossPlattform App and did not test the other plattforms, only UWP yet.

Windows 10 with Xamarin Forms 3.1.0.697729 which was the one installed for CrossPlattform.

The structure of my pages have been changed to the following:

<NavigationPage>
    <ContentPage>
        <Stacklayout or some other Content>

I have a Stack with at least one of such pages. Naming the Pages
A (Top of Stack (Modal))
B (App Main Window, normally to show after PopModalAsync or also on stack) and
C (new Window)

After returning from Page A (with "PopModalAsync") should NOT show up Page B but the new Page C instead.

I found a lot of similar examples, here in the forum, on Microsoft pages directly, on stackoverflow telling me two options:

(1)

A.Navigation.InsertPageBefore(C, A);
await Navigation.PopModalAsync();

or

(2)

await Navigation.PushModalAsync(C);
C.Navigation.RemovePage(A);

None of the both worked as expected. Both are terminating with an "System.ArgumentException".

First case (1) comes up like that:

System.ArgumentException
HResult=0x80070057
Nachricht = before must be a child of the NavigationPage
Quelle = Xamarin.Forms.Core
Stapelüberwachung:
bei Xamarin.Forms.NavigationPage.InsertPageBefore(Page page, Page before)
bei Xamarin.Forms.NavigationPage.NavigationImpl.OnInsertPageBefore(Page page, Page before)
bei Xamarin.Forms.Internals.NavigationProxy.InsertPageBefore(Page page, Page before)
bei ZZZZ.Pages.ProgressAndCancelDialog.d__28.MoveNext() in C:\ZZZZZ\Pages\ProgressAndCancelDialog.cs: Zeile197

Second case (2) comes up like that:

System.ArgumentException
HResult=0x80070057
Nachricht = Page to remove must be contained on this Navigation Page
Quelle = Xamarin.Forms.Core
Stapelüberwachung:
bei Xamarin.Forms.NavigationPage.RemovePage(Page page)
bei Xamarin.Forms.NavigationPage.NavigationImpl.OnRemovePage(Page page)
bei Xamarin.Forms.Internals.NavigationProxy.RemovePage(Page page)
bei ZZZZ.Pages.ProgressAndCancelDialog.d__28.MoveNext() in C:\ZZZZZ\Pages\ProgressAndCancelDialog.cs: Zeile198

I have no idea how to solve that issue. The first solution would be better, because of the events triggered are more similar, but I could solve it the second way. Before using the Page-Structur shown above, I did not use the NavigationPage. I added it only because of other Exceptions, which told me it's imposible using InsertBeforePage or RemovePage with other pages than NavigationPage.

When modifing case (1) like that:

(1A)

NavigationPage P = new NavigationPage(A);
P.Navigation.InsertPageBefore(C, A);
await Navigation.PopModalAsync();

The Insert works without exceptions but now the PopModalAsync() crashes like that:

System.ArgumentOutOfRangeException
HResult=0x80131502
Nachricht = Index was out of range. Must be non-negative and less than the size of the collection.
Quelle = System.Private.CoreLib
Stapelüberwachung:
bei System.ThrowHelper.ThrowArgumentOutOfRange_IndexException()
bei Xamarin.Forms.Internals.NavigationProxy.PopModal()
bei Xamarin.Forms.Internals.NavigationProxy.OnPopModal(Boolean animated)
bei Xamarin.Forms.Internals.NavigationProxy.PopModalAsync(Boolean animated)
bei Xamarin.Forms.Internals.NavigationProxy.OnPopModal(Boolean animated)
bei Xamarin.Forms.Internals.NavigationProxy.PopModalAsync()
bei ZZZZ.Pages.ProgressAndCancelDialog.d__28.MoveNext() in C:\ZZZZZ\Pages\ProgressAndCancelDialog.cs: Zeile201

After looking at the details, it becomes more clear. The ModalStack is empty after insertPageBefore, but the normal stack have the two pages as i wanted them to be.

[0] {ZZZZ.Forms.ZZZZContentPage} Xamarin.Forms.Element {ZZZZ.Forms.ZZZZContentPage}
[1] {ZZZZ.Pages.ProgressAndCancelDialog} Xamarin.Forms.Element {ZZZZ.Pages.ProgressAndCancelDialog}

where ZZZZContentpage inherits now from NavigationPage and is my Page C, the other Page A.

Using an other modification

(1B)

NavigationPage P = new NavigationPage(A);
P.Navigation.InsertPageBefore(C, A);
await Navigation.PopAsync();

has the advantage of not crashing!
But both stacks are now empty at the end of the pop-method, which is not as expected and the window A is still showing.

Even if Windows C would show up correctly as expected there would remain the problem that I could not use PopModalAsync to leave from page C, what I normally do. May be, the use of "Modal" is not necessary at all. I never understood the difference well. How should the user change back to an other page above in the stack, if the pages are all "Fullscreen" and there are no Buttons to change Pages without that i am offering and the "back" button which is ever there. Changing all away from "Modal" is some more trial to solve the issue. May be I have to make it.

Thank you in advance for any hints or suggestions.

Best Answer

Answers

  • JohnHardmanJohnHardman GBUniversity mod

    @Mitch8765

    It appears that rather than just inserting a page in the navigation stack, you are actually wanting to change the app's main page. I suggest investigating App.Current.MainPage = new NavigationPage(A); in place of InsertPageBefore.

  • LandLuLandLu Member, Xamarin Team Xamurai

    @Mitch8765 You have to figure out the difference between PushModalAsync and PushAsync:
    https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/hierarchical
    https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/modal
    http://blog.adamkemp.com/2014/09/navigation-in-xamarinforms_2.html.
    If you want to use InsertPageBefore(C, A), A should be placed in a Navigation stack. It means when you constructed the App's MainPage, it should be like this:

    public App()
    {
        InitializeComponent();
    
        MainPage = new NavigationPage(new A());
    }
    

    Or you used PushAsync API to show the A page: Navigation.PushAsync(new A());

    NavigationPage P = new NavigationPage(A);
    P.Navigation.InsertPageBefore(C, A);
    await Navigation.PopAsync();
    

    This code will not throw error messages, because A has been placed in a Navigation Stack. But as you mentioned above, pop API seems useless. Because Navigation Page P isn't shown on your current window, your code makes no sense.

    So construct your porject like:

  • JohnHardmanJohnHardman GBUniversity mod

    @LandLu - I had a look at the documentation on docs.microsoft.com at the weekend to see what it said about InsertPageBefore. I've always assumed that InsertPageBefore only works on the NavigationStack and not on modal pages, but found nothing in the documentation at the weekend to confirm that. Even looking at the XF source code, there are no comments to say whether InsertPageBefore can or cannot handle modal pages.

    The only thing that suggests it's non-modals only, was this check:

    if (InternalChildren.Contains(page))
        throw new ArgumentException("Cannot insert page which is already in the navigation stack");
    

    It might be worth clarifying the documentation to make it explicit what can and cannot be done with InsertPageBefore.

    Having said all that, I don't think that @Mitch8765 actually needs to use InsertPageBefore based on the posts above. Changing App.Current.MainPage should do what has been asked for.

  • Mitch8765Mitch8765 Member ✭✭

    **Thank you for your answers. **

    @JohnHardman: I tried that with changing the currentWindow. It seemed to me, that after doing that, the underlying Navigation Stack did not react as before. I am relatively new with Xamarin and in that moment I had not figured out viewing the Stack like at the end. I think it was empty after changing the currentWindow. But at the end it did not work. May be because I use only the ModalStack.

    @LandLu all the articles you mention I have read already. They all do only the very simple stuff. The Picture you showed me, I do not understand. What does it mean in code? The logic is clear, the structure of pages not.

    I use a framework which is constructing my pages in an abstract manner. The pages could not have dependencies from one to an other. They must be independent from each other and the connection has to come with the Navigation Stack at run time.
    The framework (now) constructs each page with his own NavigationPage as top of the logical structure. They are building together a complex form of flexible and varying Master-Details-Master-Details connections. The user can navigate freely from one object (Master) to the other depending on the logical network between the different object types.

  • JohnHardmanJohnHardman GBUniversity mod

    @Mitch8765

    TBH, because of the mix of modal and non-modal, I'd have to spend some time investigating the best way to get it to work. Unfortunately, I don't get paid for doing that :-(

    My suspicion, in the absence of good documentation, is that the easiest thing may be to not use a modal for the last page pushed. The transition when pushing a modal page on top of a non-modal page has an unexpected effect on the NavigationStack (both I and others have mentioned that in other threads). If the transition on pushing is unexpected, what happens if using InsertPageBefore after such a transition is anybody's guess. Unless you have time to investigate thoroughly, avoiding the modal is probably the easiest thing to do.

  • Mitch8765Mitch8765 Member ✭✭

    @LandLu Thank you!!!

    Really the documentation should avoid such issues. The distinction between those both methods (push and pushmodal) in relation to InsertPageBefore is never made. Maybe you could add some clarification, that there are two different stacks which operate separately. I noticed that first time while going into the internals of the implementation. It was invisible (for me) in the documentation. For me in all the documentation exists only ONE Navigation Stack, never read about two. And it could be so, even when the implementation (I found during debugging) works technical with two stacks. The implementation could handle that, but as you told me now, it does not.

    One of both has to change, implementation or documentation.

Sign In or Register to comment.