Reputation: 33
I am trying to create a custom navigation/"back" button in my mobile app. I want to bind the command as a setter property in a custom style and then apply that style to the ImageButton element in a larger custom element called HeaderNavigation.
Everything builds so that I can see my ImageButton with its styles applied. I can also see the command applied to the ImageButton when I watch its styles but, if I click on the ImageButton, the command is not called.
I've played around with the binding a little bit because I'm assuming that's the issue but no dice yet so I'm worried what I'm attempting isn't possible or maybe there's something stupid I'm missing.
Even if someone could just give me some debugging tips for mobile bindings, that would be helpful.
Thanks!
Code below:
app.xaml
<Style x:Key="NavButton" TargetType="ImageButton" BasedOn="{StaticResource IconButton}">
<Setter Property="Source" Value="back.png"/>
<Setter Property="HorizontalOptions" Value="EndAndExpand"/>
<Setter Property="Command" Value="{Binding Source={RelativeSource AncestorType={x:Type local:App}},Path=BindingContext.OnBackButtonPressed}"/>
<Setter Property="BackgroundColor" Value="{StaticResource Background}"/>
</Style>
App.xaml.cs
public async void OnBackButtonPressed(object sender, EventArgs e)
{
// I do not get called :(
_ = await Navigation.PopAsync();
}
HeaderNavigation.cs
public class HeaderNavigation : StackLayout
{
private ImageButton _returnButton;
public HeaderNavigation()
{
_returnButton = new ImageButton();
_returnButton.Style = (Style)Application.Current.Resources["NavButton"];
Children.Add(_returnButton);
}
}
}
Upvotes: 3
Views: 131
Reputation: 9438
My understanding is that your goal is to have the back button in your custom NavigationHeader
call the OnBackButtonPressed
method in your App
class:
public partial class App : Application
{
public async void OnBackButtonPressed(object sender, EventArgs e)
{
// This pop up will be the test.
await MainPage.DisplayAlert("Message from button", "It worked", "OK");
}
}
An approach that I've tested Download from GitHub to achieve the outcome you want factors in the likelihood that your custom NavigationHeader
is going to be consumed in a view of some kind (e.g. ContentPage
).
Try making this change in your Style declaration:
<Setter Property="Command" Value="{Binding BackButtonPressedCommand}" />
This way, when you consume your custom NavigationHeader e.g. in your MainPage.xaml
...
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:custom_back_button="clr-namespace:custom_back_button"
x:Class="custom_back_button.MainPage">
<StackLayout>
<custom_back_button:HeaderNavigation VerticalOptions="CenterAndExpand"/>
</StackLayout>
...the bound command will be invoked in the context of the MainPage. (Likewise, if you consume it on some other page it will soak up the BindingContext of that page.)
public partial class MainPage : ContentPage
{
public MainPage()
{
BindingContext = new MainPageBinding();
InitializeComponent();
}
}
The ICommand
is resolved in the BindingContext
resulting in a call to the OnBackButtonPressed
in this class. Now use ((App)Application.Current)
to pass the action along to the App
class as shown.
class MainPageBinding
{
public MainPageBinding()
{
BackButtonPressedCommand = new Command(OnBackButtonPressed);
}
public ICommand BackButtonPressedCommand { get; private set; }
private void OnBackButtonPressed(object o)
{
((App)Application.Current).OnBackButtonPressed(o, EventArgs.Empty);
}
}
Pressing the back button shows a successful call to the popup coded in App.OnBackButtonPressed
.
Upvotes: 1
Reputation: 21321
Two problems:
Command
needs to be bound to a Command
.
in App.xaml.cs:public Command BackButtonCommand { get; } = new Command(BackButtonAction);
private void BackButtonAction()
{
...
}
App
does not have a BindingContext
. Refer to a command on the App object itself.
Change xaml value to:... Value="{Binding Source={RelativeSource AncestorType={x:Type local:App}}, Path=BackButtonCommand}" ...
NOTE: Not tested.
Upvotes: 1