fabulous-dev / Fabulous.XamarinForms

Declarative UIs for Xamarin.Forms with F# and MVU, using Fabulous
https://docs.fabulous.dev/xamarinforms
Apache License 2.0
13 stars 1 forks source link

Question: Shell and BackButtonBehaviour/OnBackButtonPressed #14

Open gaelian opened 3 years ago

gaelian commented 3 years ago

Question / Discussion

New to Fabulous. I'm using the XF Shell for a Fabulous XF app I'm writing, currently attempting to understand how one would use BackButtonBehaviour and OnBackButtonPressed in the Fabulous DSL.

I've gotten this far:

View.Shell(
    shellBackButtonBehavior = // ???
)

Or perhaps this far:

View.ContentPage(
    shellBackButtonBehavior = // ???
)

Similarly, I'm not sure how to override OnBackButtonPressed in the context of Fabulous. Can anyone provide some example code?

TimLariviere commented 3 years ago

Hello @gaelian

Unfortunately Shell is only partially supported in Fabulous for technical reasons, so I would recommend against using it for the moment. Might be better in the upcoming MAUI rework.

Regarding your question, OnBackButtonPressed is not supported. You can use BackButtonBehavior like you showed.

BackButtonBehavior (called shellBackButtonBehavior in Fabulous) is an attached property and so is defined on pages (ContentPage) like you did, instead of on the Shell directly. shellBackButtonBehavior takes a View.BackButtonBehavior() value. You can find the various properties and events of BackButtonBehavior as parameters of View.BackButtonBehavior().

e.g.

View.Shell(
    items = [
        View.ShellContent(
            content = View.ContentPage(
                shellBackButtonBehavior = View.BackButtonBehavior(
                    command = fun () -> dispatch BackButtonClicked
                )
            )
        )
    ]
)
gaelian commented 3 years ago

Hi @TimLariviere, I appreciate the quick response.

I have been looking quite intently at the Fabimals example app, do I understand correctly in that the workarounds displayed in the source for that app represent the partial support you allude to (e.g. Routes.fs, etc)? If so, I'm hoping that I can still make it work, as otherwise, Shell seems quite perfect for what I'm trying to do. Beyond what is shown in Fabimals, are there any other "gotchas" that one should be aware of when using Shell with Fabulous?

TimLariviere commented 3 years ago

do I understand correctly in that the workarounds displayed in the source for that app represent the partial support you allude to (e.g. Routes.fs, etc)?

Yes. The thing with Shell is that it has its own routing mechanism that prevents Fabulous from knowing what's happening. Shell instantiates the pages itself when you request to move a specific URL.

Also if you need to pass parameters to a page you're navigating to (e.g. user_detail?id=XYZ), you'll need to use the QueryPropertyAttribute on the page so XF can set the properties with the correct values (Id = XYZ). This is not possible in Fabulous by default since you don't have access to the real types.

Hence the need for a custom RoutingPage class in the Fabimals sample. This one simulates a dummy page where you can load Fabulous inside. But it comes with its own set of limitations. For instance, once the page loaded, Fabulous won't be able to update it. So if you're planning more than a "read-only" page, it won't work.

gaelian commented 3 years ago

So if you're planning more than a "read-only" page, it won't work.

Ah, I see. That's very good to know. Yes, that's probably a show stopper on using Shell for me. Too bad. :(

But just out of interest, one more Shell question: I note in the Shell documentation they discuss efficient page loading. Is this something that Fabulous can or at some point will be able to take advantage of? Taking your previous example...

View.Shell(
    items = [
        View.ShellContent(
            content = View.ContentPage(
                shellBackButtonBehavior = View.BackButtonBehavior(
                    command = fun () -> dispatch BackButtonClicked
                )
            )
        )
    ]
)

Is use of the content argument able to lead to this efficient page loading feature?

TimLariviere commented 3 years ago

Is use of the content argument able to lead to this efficient page loading feature?

Yes, it's already using it. content maps directly to ShellContent.ContentTemplate in reality. So the page is only created when needed.

gaelian commented 3 years ago

That's great. So wishing I could use Shell right now.

You're doing a great job with this stuff, Tim. I'm really liking Fabulous now that I'm somewhat past F# breaking my brain. I look forward to seeing the Xamarin guys hopefully making Shell more accessible to Fabulous in the future.

Hardt-Coded commented 3 years ago

I you want to "hijack" the "hardware backbutton", you can use the navigating-event from the shell. If you don't want that the app will be closed und "e.Cancel()" to stop and implement a behaviour you want. The "e.Source" is something with "ShellXXXX.Pop" (Enum) in case you press the android back button. Don't know anything about iOS. But maybe you can uses this instead of the override backbutton thingy. At least it works for me.

For example here the back-button on an edit sub view. image

kaeedo commented 3 years ago

Is there a way to "hijack" the back button behavior when NOT using a shell? i.e., just using a NavigationPage with a ContentPage child?