The stack pattern is a fairly straightforward pattern where pages are stacked on top of each other, each page would have some sort of back button that would in turn let you pop the current page off the stack to return back to the previous page
What this means is that the application holds the current page as well as all previous pages in memory, and then releases each page from memory once it's popped off the stack.
To use the stack pattern we first need to open our App.xaml.cs file
Once you have the open you'll need to instantiate an instance of the navigation page and pass in an instance of your apps root page as a parameter.
using pav.StackNavigation.Views;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
[assembly:
XamlCompilation(XamlCompilationOptions.Compile)]
namespace pav.StackNavigation
{
public partial class App : Application
{
public App()
{
InitializeComponent();
this.MainPage = new
NavigationPage(new
MainPage());
}
protected override void
OnStart() { /* Handle when your app starts*/ }
protected override void
OnSleep() { /* Handle when your app sleeps*/ }
protected override void
OnResume() { /* Handle when your app resumes*/ }
}
}
This will allow us to leverage the stack navigation pattern with minimal effort.
next lets' create a second "Content Page"
this will give us a page to push onto and pop off our navigation stack. Now let's open up our Main Page and add a Push Button.
<?xml
version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="pav.StackNavigation.Views.MainPage">
<StackLayout>
<!--label-->
<Label Text="Welcome
to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
/>
<!--Push
Button-->
<Button x:Name="Push_Button"
Text="Push
Page"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
/>
</StackLayout>
</ContentPage>
using Xamarin.Forms;
namespace pav.StackNavigation.Views
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
Push_Button.Clicked += async (s, e) => await this.Navigation.PushAsync(new SecondPage());
}
}
}
Our main page's navigation object is auto-magically wired up to leverage the use of the Navigation stack using dependency injection under the hood.
Next let's open up our Second page and add a pop button
<?xml
version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="pav.StackNavigation.Views.SecondPage">
<ContentPage.Content>
<StackLayout>
<!--Label-->
<Label Text="This
is the second page"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<!--Pop
Button-->
<Button x:Name="Pop_Button"
Text="Pop this
page"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
now that we have our pop button let's wire it up in the codebehind.
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace pav.StackNavigation.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SecondPage : ContentPage
{
public SecondPage ()
{
InitializeComponent ();
Pop_Button.Clicked += async (s,e) => await this.Navigation.PopAsync();
}
}
}
and that's it we're now using a stack navigation with minimal effort.
Navigation bar Customization
To modify the look and feel of the navigation bar we have to go back to our app.xaml.cs page.
using pav.StackNavigation.Views;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
[assembly:
XamlCompilation(XamlCompilationOptions.Compile)]
namespace pav.StackNavigation
{
public partial class App : Application
{
public App()
{
InitializeComponent();
this.MainPage = new
NavigationPage(new
MainPage()) {
BarBackgroundColor =
Color.Maroon,
BarTextColor = new Color(256, 256, 256),
BackgroundColor = new Color(256, 0, 0, .2)
};
}
protected override void
OnStart() { /* Handle when your app starts*/ }
protected override void
OnSleep() { /* Handle when your app sleeps*/ }
protected override void
OnResume() { /* Handle when your app resumes*/ }
}
}
with the above modifications made our app we see the following changes:
now these changes are consistent throughout our entire navigation model, so no matter where we are in our navigation stack we'll have a consistent theme.
You may have noticed that in the above our navigation bar has a page title, this can be accomplished declarative-ly in xaml or programatically in the code-behind
<?xml
version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="Home"
x:Class="pav.StackNavigation.Views.MainPage">
<StackLayout>
<!--label-->
<Label Text="Welcome
to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
/>
<!--Push
Button-->
<Button x:Name="Push_Button"
Text="Push
Page"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
/>
</StackLayout>
</ContentPage>
Finally we can override a back button being pressed, generally we'd never want to do this because it could lead to confusion, with the user thinking that your app has frozen or isn't working correctly because it breaks an established paradigm, but with every rule there's always that one exception, anyway to do this you'd simple override the OnBackButtonPressed function.
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace pav.StackNavigation.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SecondPage : ContentPage
{
public SecondPage()
{
InitializeComponent();
Pop_Button.Clicked += async (s, e) => await this.Navigation.PopAsync();
NavigationPage.SetHasBackButton(this, false);
}
protected override bool
OnBackButtonPressed()
{
return true; // block back button
return false; // normal back button behavoir
}
}
}
with overriding the OnBackButtonPressed behavior we disabled the back button functionality and in the constructor we hid the virtual back button, in this situation we have to handle poping our page off our navigation stack ourselves, which we previously did in the Pop_button's event handler.