Xamarin.forms: [Shell] BackButtonBehavior issues

Created on 29 Mar 2019  路  12Comments  路  Source: xamarin/Xamarin.Forms

Description

BackButtonBehavior seems like it has some holes in it. Here's my issues:

  1. Its name. It's not a Behavior. How about BackButtonOptions or BackButtonConfiguration?
  2. Once you set a BackButtonBehavior on a ContentPage, you automatically lose the default back arrow, and have to set your own (on iOS).
  3. I like the commanding model. Maybe it should have a Clicked event too? Are there scenarios where users will want to handle a back button intercept in their page code-behind, while still having the page BindingContext set to a ViewModel?
  4. It seems like a typical scenario would be binding BackButtonBehavior.Command to an ICommand in a ViewModel. The idea being that you can intercept the back button press, and display an alert if there's unsaved data on the page, and cancel navigation if required. However, there's no easy way to cancel navigation in this scenario.
  5. https://github.com/xamarin/Xamarin.Forms/issues/5734
shell bug

Most helpful comment

THANKS!

All 12 comments

Related work that was done on this
https://github.com/xamarin/Xamarin.Forms/issues/4767

I'm having the same problem. I'm using the latest and anytime I try to set the Command on BackButtonBehavior, it crashes on the ContentPage (when trying to load) with a NullReferenceException. I have confirmed that the Command is built and ViewModel has been assigned to the BindingContext of the ContentPage:

<ContentPage x:Class="Sample.Views.SettingsView"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:Sample.Controls"
             x:Name="PART_SettingsView">

    <Shell.TitleView>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Label Grid.Column="0"
                   Style="{StaticResource BlockLabel}"
                   Text="{Binding BindingContext.Title, Source={x:Reference Name=PART_SettingsView}}" />

            <Button Grid.Column="2"
                    Command="{Binding BindingContext.SaveCommand, Source={x:Reference Name=PART_SettingsView}}"
                    Style="{StaticResource BlockIconButton}"
                    Text="{Binding BindingContext.SaveCommandText, Source={x:Reference Name=PART_SettingsView}}" />
        </Grid>
    </Shell.TitleView>

    <Shell.BackButtonBehavior>
        <BackButtonBehavior BindingContext="{Binding BindingContext, Source={x:Reference PART_SettingsView}}"
                            Command="{Binding BackCommand}" />
    </Shell.BackButtonBehavior>

    <Grid>
        <controls:SettingsEditor Settings="{Binding Settings}" />
    </Grid>
</ContentPage>

As a side note, the SaveCommand works totally fine. I've also tried to have the BackButtonBehavior marked up in the same manner as SaveCommand (I had read that BindingContext was needed to be set on the Behavior to make it "work"), but no luck.

I'm working on this along with some route navigation behavior also
https://github.com/xamarin/Xamarin.Forms/tree/shell_route_navigation

We will keep the name BackButtonBehavior because there's precedence for it

Hey guys. First, thanks for Xamarin! Definitely my favorite mobile development platform, although I'm a little novice to it. I'm getting messed up by this issue though in a new Shell application for a client. Is there a workaround for now?

@dunlavy we're still refining this to make this all work a bit smoother but what are you specifically trying to do and maybe I can help give you a workaround?

Just this:

<Shell.BackButtonBehavior>
    <BackButtonBehavior Command="{Binding BackButtonCommand}" />
</Shell.BackButtonBehavior>

I do have my viewmodel set in BindingContext and my other bindings resolve nicely.

If I comment out the above XAML when I load my page, everything is fine. Take out the comments so the code is active and:

System.NullReferenceException: Object reference not set to an instance of an object.

I'd really like to use the Shell approach to overriding back button behavior. If Shell is currently broken in this regard, I'm assuming there's a slightly more verbose Xamarin.Forms method to doing this?

Appreciate the time and effort guys!

^ In other words, I encounter roughly the same as https://github.com/xamarin/Xamarin.Forms/issues/5744#issuecomment-489812181.

@dunlavy can you post the full stack trace so i can see what specifically is causing your NRE

For your reference, I'm running in an Android emulator on Windows.
(the trace consists entirely of external code)

Here you go!:

Unhandled Exception:

System.NullReferenceException: Object reference not set to an instance of an object. occurred

0xFFFFFFFFFFFFFFFF in System.Diagnostics.Debugger.Mono_UnhandledException_internal
0x1 in System.Diagnostics.Debugger.Mono_UnhandledException
0x20 in Android.Runtime.DynamicMethodNameCounter.79
0x12 in System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw
0x6 in System.Runtime.CompilerServices.AsyncMethodBuilderCore.<>c.<ThrowAsync>b__6_0
0xC in Android.App.SyncContext.
0xE in Java.Lang.Thread.RunnableImplementor.Run
0xA in Java.Lang.IRunnableInvoker.n_Run
0x11 in Android.Runtime.DynamicMethodNameCounter.79

I sure hope that's helpful. My code is super basic:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:d="http://xamarin.com/schemas/2014/forms/design"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:vm="clr-namespace:----.ViewModels"
                 mc:Ignorable="d"
                 x:Class="----.Views.AboutPage"
                 Title="{Binding AboutTitle}">
    <ContentPage.BindingContext>
        <vm:AboutViewModel />
    </ContentPage.BindingContext>

    <ContentPage.Resources>
        <ResourceDictionary>...

``` c#
namespace ----.ViewModels {
public class AboutViewModel : BaseViewModel {
public AboutViewModel() {
BackButtonCommand = new Command(
execute: () => Shell.Current.GoToAsync("guest")
);

        OpenWebCommand = new Command(
            execute: () => Device.OpenUri(new Uri("https://xamarin.com/platform"))
        );
    }

    public ICommand BackButtonCommand { get; private set; }
    public ICommand OpenWebCommand { get; private set; }
}

}
```

I'm having the same problem. I'm using the latest and anytime I try to set the Command on BackButtonBehavior, it crashes on the ContentPage (when trying to load) with a NullReferenceException. I have confirmed that the Command is built and ViewModel has been assigned to the BindingContext of the ContentPage:

<ContentPage x:Class="Sample.Views.SettingsView"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:Sample.Controls"
             x:Name="PART_SettingsView">

    <Shell.TitleView>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <Label Grid.Column="0"
                   Style="{StaticResource BlockLabel}"
                   Text="{Binding BindingContext.Title, Source={x:Reference Name=PART_SettingsView}}" />

            <Button Grid.Column="2"
                    Command="{Binding BindingContext.SaveCommand, Source={x:Reference Name=PART_SettingsView}}"
                    Style="{StaticResource BlockIconButton}"
                    Text="{Binding BindingContext.SaveCommandText, Source={x:Reference Name=PART_SettingsView}}" />
        </Grid>
    </Shell.TitleView>

    <Shell.BackButtonBehavior>
        <BackButtonBehavior BindingContext="{Binding BindingContext, Source={x:Reference PART_SettingsView}}"
                            Command="{Binding BackCommand}" />
    </Shell.BackButtonBehavior>

    <Grid>
        <controls:SettingsEditor Settings="{Binding Settings}" />
    </Grid>
</ContentPage>

As a side note, the SaveCommand works totally fine. I've also tried to have the BackButtonBehavior marked up in the same manner as SaveCommand (I had read that BindingContext was needed to be set on the Behavior to make it "work"), but no luck.

Were you ever able to address this? I'm hoping it's nothing I did but if it's something I borked then I can at least correct it in a timely manner. Even attempting to disable back button behavior with Shell.BackButtonBehavior does exactly what you described.

As much as I'd like to use the clean Shell implementation, I may just refer to https://theconfuzedsourcecode.wordpress.com/2017/03/12/lets-override-navigation-bar-back-button-click-in-xamarin-forms/

Seems like this issue is in progress on the board, though. :-)

I guess a better question: Can anyone create BackButtonBehavior in any way and use it reliably in a current Xamarin.Forms application? Is this a confirmed Xamarin.Forms bug or are we messing up our projects somehow?

THANKS!

Was this page helpful?
0 / 5 - 0 ratings