xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.64k stars 1.88k forks source link

[Enhancement] Decouple Shell Flyout and Navigation. #12800

Open glatzert opened 3 years ago

glatzert commented 3 years ago

Summary

We use AppShell in a not very complex application with ~10 top-level routes and some second level navigations, which do not fit into tabbed navigation. AppShell has been brought into the app especially for the flyout and for the navigation capabilities. Unfortunately Flyout and Routing seem to be tighlty coupled, which has some drawbacks:

API Changes

Intended Use Case

This can be used to have a simple and robust navigation to anything and allow us developers to modify the contents of the flyout as we see fit. By decoupling navigation and Flyout, it might also be possible to use all sorts of pages in combination with shell.

PureWeen commented 3 years ago

@glatzert can you elaborate on this point? Give me an example where you're having to change it up based on where you are?

glatzert commented 3 years ago

Consider having /animals/monkey/details in Shell. Also globally Register /animals/care-takers/details during App-Startup.

Now assume being on /animals/care-takers/details?name=Frank and try to link /animals/monkey/details?name=Baboon. The expected route (if we talk about quasi-URLs here) would be ../../monkey/details?name=Baboon.

But the docs state

If we link the other way:

So the "same" navigation steps require two different scenarios (if not more, due to .. being back). I think there'll be more havoc, since the routes do intertwine, but I hope the gist is clear.

It seem to get especially harsh, if you want to place routes into the shell-routing-hierarchy ^^.

I think the basic problem here stems from the fact, shell is trying to have this "shell-content" thing, which (I'd say) is not the main selling point for shell. The top feature of shell is a presumely unified navigation and the flyout itself. The latter one giving everything a frame to be "an application". Coming from WPF, I did expect flyout to behave more or less like PrismLibraries Regions, but somehow it intertwines routes and the routes content via the flyout and that seems to overcoplicate things.

If you like, I can show or send our source code - since we are working for a university, there's (nearly) nothing secret in the code.

PureWeen commented 3 years ago

@glatzert If you could send me code that'd be helpful shneuvil at microsoft.com Or just post here

The main limitation with pushing is that global routes can't be the first page and you can't push shell content (unfortunate limitations but just setting a starting point)

I'm not the biggest fan of calling shell "URI navigation". In hindsight we would have just removed all references to URI and called it "path" navigation. If we stuck with URI's then we should make it so each URI was unique and you'd just have stacks of URI's (it sounds like this is how you're thinking it works which is understandable)

But how it works is fundamentally like PRISM. You could give everything a unique string name and just concatenate paths

<ShellContent Route="shellroute" RegisterRoute("globalroute")

//shellroute/globalroute/globalroute/globalroute

This indicates a shell content that's active and then 3 pages that are pushed to the stack

The only reason in global routes to register a full uri is that you are specifying where you need to be for a route to be valid

so if your shell file looks like this

<Tab route="animals">
     <ShellContent Route="monkeys" />
     <ShellContent Route="bears" />
     <ShellContent Route="cats" />
</Tab>

Then you can register a global route like

"animals/bears/details" "animals/cats/details" "animals/monkeys/details"

So now if the user is at

//animals/monkeys then you can call GotoAsync("Details") and it will push the page you registered at animals/bears/details

Think of it like you've specified your shell routes like this (which is how I hope to one day make it)

<Tab route="animals">
     <ShellContent Route="monkeys">
             <ShellContent Route="details">
             </ShellContent>
     </ShellContent>
     <ShellContent Route="bears" />
     <ShellContent Route="cats" />
</Tab>

There are some issues that I'm fixing in 5.0 https://github.com/xamarin/Xamarin.Forms/pull/13330 That might have made this a bit more confusing because certain scenarios aren't working like promised :-/

glatzert commented 3 years ago

Thanks for your write up. I think this makes some things clearer for me - and unfortunately it seems, Shell is no solution to our problems - which means we'll probably take the render-parts of shell and see where to get a stack-based uri-navigation (as in a browser).

We misuse Flyout as container for different things (using MenuItem to get around), so we also need to swap that component into something which is flexible. My impression here is, that you have a very specific use case in mind, which does not align with our use case of having a container which allows us to put whatever we like into it.