Reputation: 9115
I am using ControlTemplate
have consistent Navigation Bar accross Android and iOS
<ControlTemplate x:Key="NavBarTemplate">
<StackLayout>
<StackLayout Orientation="Horizontal"
VerticalOptions="CenterAndExpand"
IsVisible="{TemplateBinding BindingContext.IsBackButtonVisible, Mode=TwoWay}">
<Label Text="<"
FontSize="Large"
FontAttributes="Bold"
HorizontalTextAlignment="Center"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center"
Margin="20,0,0,0" />
<Label TextColor="{StaticResource DarkGrey}"
HorizontalOptions="StartAndExpand"
HorizontalTextAlignment="Center"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center"
FontSize="Small"
Text="Back" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{TemplateBinding BindingContext.NavigateBackCommand}" />
</StackLayout.GestureRecognizers>
</StackLayout>
<Image Source="logo.png"
VerticalOptions="Center" />
</StackLayout>
</ControlTemplate>
In order to dynamically display back button I have added below code in OnAppearing
of BasePage.cs
protected override void OnAppearing ()
{
base.OnAppearing ();
if (BindingContext is BaseViewModel viewmodel)
{
if(Application.Current.MainPage as NavigationPage nav)
{
if(nav.Navigation.NavigationStack.Count >1 )
{
viewmodel.IsBackButtonVisible = true;
}else
{
viewmodel.IsBackButtonVisible = false;
}
//dirty coding force to false
if (!this.IsBackButtonVisible) //refers to local BindableProperty
{
viewmodel.IsBackButtonVisible = false;
}
}else //no viewmodel found just use localbinding
{
BindingContext = this;
}
}
}
So in some pages I want to enforce Back button off even though NavigationStack
is > 1
Right now I am achieving based on Dirty coding above by having BindableProperty
in the BasePage with same name IsBackButtonVisible
My question is , is there a way to do alternative binding for ControlTemplate
, I know there is FallBackValue and Default for normal Binding( which are just values not binding ofcourse) but I dont want to hard code it and seems TemplateBinding doesnt support those(intellisence wont show these options)
What I want to do is rename BindableProperty
in BasePage
to ForceNoBackButton
and make navigation bar invisible despite of ViewModel binding.
Is there any way to do alternative binding in TemplateBinding
based on conditions..
If BindingContext is type of BaseViewModel then use Property IsBackButtonVisible
Else if page BindingContext
is this page or something other than BaseViewModel
then fallback to BasePage
local BindableProperty
i.e ForceNoBackButton
Can I do it with propertychanged event handler of BindableProperty ? If yes, how. I know how to do it if the visual element is in the current XAML, dont know how to do it for TemplatedView
Upvotes: 0
Views: 522
Reputation: 13591
You can create two bindable properties IsBackButtonVisible
and ForceNoBackButton
on BasePage
.
public static readonly BindableProperty ForceNoBackButtonProperty =
BindableProperty.Create(
"ForceNoBackButton", typeof(bool), typeof(BasePage),
defaultValue: default(bool));
public static readonly BindableProperty IsBackButtonVisibleProperty =
BindableProperty.Create(
"IsBackButtonVisible", typeof(bool), typeof(BasePage),
defaultValue: default(bool));
And update your control-template to simply use IsBackButtonVisible
<ControlTemplate x:Key="NavBarTemplate">
...
<StackLayout Orientation="Horizontal"
..
IsVisible="{TemplateBinding IsBackButtonVisible}">
while modifying OnAppearing()
method as follows:
protected override void OnAppearing()
{
..
if (nav.Navigation.NavigationStack.Count > 1)
{
IsBackButtonVisible = !ForceNoBackButton;
}
else
{
IsBackButtonVisible = false;
}
To keep the associated viewmodel in sync with this property - you can either set binding on BasePage.xaml
, or add following line in BasePage()
constructor to set this binding programmatically.
public BasePage()
{
InitializeComponent();
SetBinding(IsBackButtonVisibleProperty,
new Binding(nameof(BaseViewModel.IsBackButtonVisible),
mode: BindingMode.OneWayToSource));
}
Would also recommend to have a property-changed handler for ForceNoBackButton
- so you can handle changes to it's value (if they happen after the page has already loaded).
Upvotes: 1