Page Navigation with Xamarin.Forms

Xamarin.Forms provides a number of different page navigation experiences, depending upon the Page type being used. These experiences include ContentPage, MasterDetailPage, TabbedPage and CarouselPage.

Hierarchical Navigation

The NavigationPage class provides a hierarchical navigation experience where the user is able to navigate through pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO) stack of Page objects.

Navigating through a stack of pages

The NavigationPage class provides a hierarchical navigation experience where the user is able to navigate through pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO) stack of Page objects. This article demonstrates how to use the NavigationPage class to perform navigation in a stack of pages.

  • Performing navigation: creating the root page, pushing pages to the navigation stack, popping pages from the navigation stack, and animating page transitions.
  • Passing data when navigating: passing data through a page constructor, and through a BindingContext.
  • Manipulating the navigation stack: manipulating the stack by inserting or removing pages.

To move from one page to another, an application will push a new page onto the navigation stack, where it will become the active page, as shown in the following diagram:

To return back to the previous page, the application will pop the current page from the navigation stack, and the new topmost page becomes the active page, as shown in the following diagram:

Performing Navigation

In hierarchical navigation, the NavigationPage class is used to navigate through a stack of Contentpage objects. The following screenshots show the main components of the NavigationPage on each platform:

The layout of a NavigationPage is dependent on the platform:

  • On iOS, a navigation bar is present at the top of the page that displays a title, and that has a Back button that returns to the previous page.
  • On Android, a navigation bar is present at the top of the page that displays a title, an icon, and a Back button that returns to the previous page. The icon is defined in the [Activity] attribute that decorates the MainActivity class in the Android platform-specific project.
  • On Windows Phone, a navigation bar is present at the top of the page that displays a title. Windows Phone lacks the Back button on the navigation bar because an on-screen Back button is present at the bottom of the screen.

On all the platforms, the value of the Page.Title property will be displayed as the page title.

It's recommended that a NavigationPage should be populated with ContentPage instances only.

Creating the Root Page

The first page added to a navigation stack is referred to as the root page of the application, and the following code example shows how this is accomplished:

public App ()
{
  MainPage = new NavigationPage (new Page1Xaml ());
}

This causes the Page1Xaml ContentPage instance to be pushed onto the navigation stack, where it becomes the active page and the root page of the application. This is shown in the following screenshots:

Pushing Pages to the Navigation Stack

To navigate to Page2Xaml, it is necessary to invoke the PushAsync method on the Navigation property of the current page, as demonstrated in the following code example:

async void OnNextPageButtonClicked (object sender, EventArgs e)
{
  await Navigation.PushAsync (new Page2Xaml ());
}

This causes the Page2Xaml instance to be pushed onto the navigation stack, where it becomes the active page. This is shown in the following screenshots:

When the PushAsync method is invoked, the following events occur:

  • The page calling PushAsync has its OnDisappearing override invoked.
  • The page being navigated to has its OnAppearing override invoked.
  • The PushAsync task completes.

However, the precise order in which these events occur is platform dependent.

Calls to the OnDisappearing and OnAppearing overrides cannot be treated as guaranteed indications of page navigation. For example, on iOS, the OnDisappearing override is called on the active page when the application terminates.

Popping Pages from the Navigation Stack

The active page can be popped from the navigation stack by pressing the Back button on the device, regardless of whether this is a physical button on the device or an on-screen button.

To programmatically return to the original page, the Page2Xaml instance must invoke the PopAsync method, as demonstrated in the following code example:

async void OnPreviousPageButtonClicked (object sender, EventArgs e)
{
  await Navigation.PopAsync ();
}

This causes the Page2Xaml instance to be removed from the navigation stack, with the new topmost page becoming the active page. When the PopAsync method is invoked, the following events occur:

  • The page calling PopAsync has its OnDisappearing override invoked.
  • The page being returned to has its OnAppearing override invoked.
  • The PopAsync task returns.

However, the precise order in which these events occur is platform dependent.

As well as PushAsync and PopAsync methods, the Navigation property of each page also provides a PopToRootAsync method, which is shown in the following code example:

async void OnRootPageButtonClicked (object sender, EventArgs e)
{
  await Navigation.PopToRootAsync ();
}

This method pops all but the root Page off of the navigation stack, therefore making the root page of the application the active page.

Animating Page Transitions

The Navigation property of each page also provides overridden push and pop methods that include a boolean parameter that controls whether to display a page animation during navigation, as shown in the following code example:

async void OnNextPageButtonClicked (object sender, EventArgs e)
{
  // Page appearance not animated
  await Navigation.PushAsync (new Page2Xaml (), false);
}

async void OnPreviousPageButtonClicked (object sender, EventArgs e)
{
  // Page appearance not animated
  await Navigation.PopAsync (false);
}

async void OnRootPageButtonClicked (object sender, EventArgs e)
{
  // Page appearance not animated
  await Navigation.PopToRootAsync (false);
}

Setting the boolean parameter to false disables the page-transition animation, while setting the parameter to true enables the page-transition animation, provided that it is supported by the underlying platform. However, the push and pop methods that lack this parameter enable the animation by default.

Passing Data when Navigating

Sometimes it's necessary for a page to pass data to another page during navigation. Two techniques for accomplishing this are passing data through a page constructor, and by setting the new page's BindingContext to the data. Each will now be discussed in turn.

Passing Data through a Page Constructor

The simplest technique for passing data to another page during navigation is through a page constructor parameter, which is shown in the following code example:

public App ()
{
  MainPage = new NavigationPage (new MainPage (DateTime.Now.ToString ("u")));
}

This code creates a MainPage instance, passing in the current date and time in ISO8601 format, which is wrapped in a NavigationPage instance.

The MainPage instance receives the data through a constructor parameter, as shown in the following code example:

public MainPage (string date)
{
  InitializeComponent ();
  dateLabel.Text = date;
}

The data is then displayed on the page by setting the Label.Text property, as shown in the following screenshots:

Passing Data through a BindingContext

An alternative approach for passing data to another page during navigation is by setting the new page's BindingContext to the data, as shown in the following code example:

async void OnNavigateButtonClicked (object sender, EventArgs e)
{
  var contact = new Contact {
    Name = "Jane Doe",
    Age = 30,
    Occupation = "Developer",
    Country = "USA"
  };

  var secondPage = new SecondPage ();
  secondPage.BindingContext = contact;
  await Navigation.PushAsync (secondPage);
}

This code sets the BindingContext of the SecondPage instance to the Contact instance, and then navigates to the SecondPage.

The SecondPage then uses data binding to display the Contact instance data, as shown in the following XAML code example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="PassingData.SecondPage"
             Title="Second Page">
    <ContentPage.Content>
        <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
            <StackLayout Orientation="Horizontal">
                <Label Text="Name:" HorizontalOptions="FillAndExpand" />
                <Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
            </StackLayout>
            ...
            <Button x:Name="navigateButton" Text="Previous Page" Clicked="OnNavigateButtonClicked" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

The following code example shows how the data binding can be accomplished in C#:

public class SecondPageCS : ContentPage
{
  public SecondPageCS ()
  {
    var nameLabel = new Label {
      FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
      FontAttributes = FontAttributes.Bold
    };
    nameLabel.SetBinding (Label.TextProperty, "Name");
    ...
    var navigateButton = new Button { Text = "Previous Page" };
    navigateButton.Clicked += OnNavigateButtonClicked;

    Padding = new Thickness (0, Device.OnPlatform (20, 0, 0), 0, 0);
    Content = new StackLayout {
      HorizontalOptions = LayoutOptions.Center,
      VerticalOptions = LayoutOptions.Center,
      Children = {
        new StackLayout {
          Orientation = StackOrientation.Horizontal,
          Children = {
            new Label{ Text = "Name:", FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)), HorizontalOptions = LayoutOptions.FillAndExpand },
            nameLabel
          }
        },
        ...
        navigateButton
      }
    };
  }

  async void OnNavigateButtonClicked (object sender, EventArgs e)
  {
    await Navigation.PopAsync ();
  }
}

The data is then displayed on the page by a series of Label controls, as shown in the following screenshots:

Manipulating the Navigation Stack

The Navigation property exposes a NavigationStack property from which the pages in the navigation stack can be obtained. While Xamarin.Forms maintains access to the navigation stack, the Navigation property provides the InsertPageBefore and RemovePage methods for manipulating the stack by inserting pages or removing them.

The InsertPageBefore method inserts a specified page in the navigation stack before an existing specified page, as shown in the following diagram:

The RemovePage method removes the specified page from the navigation stack, as shown in the following diagram:

These methods enable a custom navigation experience, such as replacing a login page with a new page, following a successful login. The following code example demonstrates this scenario:

async void OnLoginButtonClicked (object sender, EventArgs e)
{
  ...
  var isValid = AreCredentialsCorrect (user);
  if (isValid) {
    App.IsUserLoggedIn = true;
    Navigation.InsertPageBefore (new MainPage (), this);
    await Navigation.PopAsync ();
  } else {
    // Login failed
  }
}

Provided that the user's credentials are correct, the MainPage instance is inserted into the navigation stack before the current page. The PopAsync method then removes the current page from the navigation stack, with the MainPage instance becoming the active page.

This section demonstrated how to use the NavigationPage class to perform navigation in a stack of pages. This class provides a hierarchical navigation experience where the user is able to navigate through pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO) stack of Page objects.

TabbedPage

The Xamarin.Forms TabbedPage consists of a list of tabs and a larger detail area, with each tab loading content into the detail area.

Navigating between pages using tabs

The Xamarin.Forms TabbedPage consists of a list of tabs and a larger detail area, with each tab loading content into the detail area. This article demonstrates how to use a TabbedPage to navigate through a collection of pages.

The following screenshots show a TabbedPage on each platform:

The following screenshots focus on the tab format on each platform:

The layout of a TabbedPage, and its tabs, is dependent on the platform:

  • On iOS, the list of tabs appears at the bottom of the screen, and the detail area is above. Each tab also has an icon image which should be a 30x30 PNG with transparency for normal resolution, 60x60 for high resolution, and 90x90 for iPhone 6 Plus resolution. If there are more than five tabs, a More tab will appear, which can be used to access the additional tabs. For more information about loading images in a Xamarin.Forms application, see Working with Images. For more information about icon requirements, see Creating Tabbed Applications.
  • On Android, the list of tabs appears at the top of the screen, and the detail area is below. The tab names are automatically capitalized, and the user can scroll the collection of tabs if there are too many to fit on one screen.
  • On Windows Phone, the list of tabs appears at the top of the screen, and the detail area is below. The tab names are automatically converted to lowercase, and the user can scroll the collection of tabs if there are too many to fit on one screen.
  • On Windows tablet form-factors, the tabs aren't always visible and users need to swipe-down (or right-click, if they have a mouse attached) to view the tabs in a TabbedPage (as shown below).

Creating a TabbedPage

Two approaches can be used to create a TabbedPage:

  • Populate the TabbedPage with a collection of child Page objects, such as a collection of ContentPage instances.
  • Assign a collection to the ItemsSource property and assign a DataTemplate to the ItemTemplate property to return pages for objects in the collection.

With both approaches, the TabbedPage will display each page as the user selects each tab.

It's recommended that a TabbedPage should be populated with NavigationPage and ContentPage instances only. This will help to ensure a consistent user experience across all platforms.

Populating a TabbedPage with a Page Collection

The following XAML code example shows a TabbedPage constructed by populating it with a collection of child Page objects:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:local="clr-namespace:TabbedPageWithNavigationPage;assembly=TabbedPageWithNavigationPage"
            x:Class="TabbedPageWithNavigationPage.MainPage">
    <local:TodayPage />
    <NavigationPage Title="Schedule" Icon="schedule.png">
        <x:Arguments>
            <local:SchedulePage />
        </x:Arguments>
    </NavigationPage>
</TabbedPage>

The following code example shows the equivalent TabbedPage created in C#:

public class MainPageCS : TabbedPage
{
  public MainPageCS ()
  {
    var navigationPage = new NavigationPage (new SchedulePageCS ());
    navigationPage.Icon = "schedule.png";
    navigationPage.Title = "Schedule";

    Children.Add (new TodayPageCS ());
    Children.Add (navigationPage);
  }
}

The TabbedPage is populated with two child Page objects. The first child is a ContentPage instance, and the second tab is a NavigationPage containing a ContentPage instance.

The TabbedPage does not support UI virtualization. Therefore, performance may be affected if the TabbedPage contains too many child elements.

The following screenshots show the TodayPage ContentPage instance, which is shown on the Today tab:

Selecting the Schedule tab displays the SchedulePage ContentPage instance, which is wrapped in a NavigationPage instance, and is shown in the following screenshot:

For information about the layout of a NavigationPage, see Performing Navigation.

Navigation Inside a Tab

Navigation can be performed from the second tab by invoking the PushAsync method on the Navigation property of the ContentPage instance, as demonstrated in the following code example:

async void OnUpcomingAppointmentsButtonClicked (object sender, EventArgs e)
{
  await Navigation.PushAsync (new UpcomingAppointmentsPage ());
}

This causes the UpcomingAppointmentsPage instance to be pushed onto the navigation stack, where it becomes the active page. This is shown in the following screenshots:

For more information about performing navigation using the NavigationPage class, see Hierarchical Navigation.

Populating a TabbedPage with a Template

The following XAML code example shows a TabbedPage constructed by assigning a DataTemplate to the ItemTemplateproperty to return pages for objects in the collection:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:TabbedPageDemo;assembly=TabbedPageDemo"
            x:Class="TabbedPageDemo.TabbedPageDemoPage">
  <TabbedPage.Resources>
    <ResourceDictionary>
      <local:NonNullToBooleanConverter x:Key="booleanConverter" />
    </ResourceDictionary>
  </TabbedPage.Resources>
  <TabbedPage.ItemTemplate>
    <DataTemplate>
      <ContentPage Title="{Binding Name}" Icon="monkeyicon.png">
        <StackLayout Padding="5, 25">
          <Label Text="{Binding Name}" Font="Bold,Large" HorizontalOptions="Center" />
          <Image Source="{Binding PhotoUrl}" WidthRequest="200" HeightRequest="200" />
          <StackLayout Padding="50, 10">
            <StackLayout Orientation="Horizontal">
              <Label Text="Family:" HorizontalOptions="FillAndExpand" />
              <Label Text="{Binding Family}" Font="Bold,Medium" />
            </StackLayout>
            ...
          </StackLayout>
        </StackLayout>
      </ContentPage>
    </DataTemplate>
  </TabbedPage.ItemTemplate>
</TabbedPage>

The TabbedPage is populated with data by setting the ItemsSource property in the constructor for the code-behind file:

public TabbedPageDemoPage ()
{
  ...
  ItemsSource = MonkeyDataModel.All;
}

The following code example shows the equivalent TabbedPage created in C#:

public class TabbedPageDemoPageCS : TabbedPage
{
  public TabbedPageDemoPageCS ()
  {
    var booleanConverter = new NonNullToBooleanConverter ();

    ItemTemplate = new DataTemplate (() => {
      var nameLabel = new Label {
        FontSize = Device.GetNamedSize (NamedSize.Large, typeof(Label)),
        FontAttributes = FontAttributes.Bold,
        HorizontalOptions = LayoutOptions.Center
      };
      nameLabel.SetBinding (Label.TextProperty, "Name");

      var image = new Image { WidthRequest = 200, HeightRequest = 200 };
      image.SetBinding (Image.SourceProperty, "PhotoUrl");

      var familyLabel = new Label {
        FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
        FontAttributes = FontAttributes.Bold
      };
      familyLabel.SetBinding (Label.TextProperty, "Family");
      ...

      var contentPage = new ContentPage {
        Icon = "monkeyicon.png",
        Content = new StackLayout {
          Padding = new Thickness (5, 25),
          Children = {
            nameLabel,
            image,
            new StackLayout {
              Padding = new Thickness (50, 10),
              Children = {
                new StackLayout {
                  Orientation = StackOrientation.Horizontal,
                  Children = {
                    new Label { Text = "Family:", HorizontalOptions = LayoutOptions.FillAndExpand },
                    familyLabel
                  }
                },
                ...
              }
            }
          }
        }
      };
      contentPage.SetBinding (TitleProperty, "Name");
      return contentPage;
    });
    ItemsSource = MonkeyDataModel.All;
  }
}

Each tab displays a ContentPage that uses a series of StackLayout and Label instances to display data for the tab. The following screenshots show the content for the Tamarin tab:

Selecting another tab then displays content for that tab.

The TabbedPage does not support UI virtualization. Therefore, performance may be affected if the TabbedPage contains too many child elements.

This section demonstrated how to use a TabbedPage to navigate through a collection of pages. The Xamarin.Forms TabbedPage consists of a list of tabs and a larger detail area, with each tab loading content into the detail area.

Swiping from right to left moves to the second page, as shown in the following screenshots:

CarouselPage

The Xamarin.Forms CarouselPage is a page that users can swipe from side to side to navigate through pages of content, like a gallery.

Navigating between pages using a swipe gesture

The Xamarin.Forms CarouselPage is a page that users can swipe from side to side to navigate through pages of content, like a gallery. This article demonstrates how to use a CarouselPage to navigate through a collection of pages.

The following screenshots show a CarouselPage on each platform:

The layout of a CarouselPage is identical on each platform. Pages can be navigated through by swiping right to left to navigate forwards through the collection, and by swiping left to right to navigate backwards through the collection. The following screenshots show the first page in a CarouselPage instance:

Swiping from right to left again moves to the third page, while swiping from left to right returns to the previous page.

Creating a CarouselPage

Two approaches can be used to create a CarouselPage:

  • Populate the CarouselPage with a collection of child ContentPage instances.
  • Assign a collection to the ItemsSource property and assign a DataTemplate to the ItemTemplate property to return ContentPage instances for objects in the collection.

With both approaches, the CarouselPage will then display each page in turn, with a swipe interaction moving to the next page to be displayed. This navigation experience will feel natural and familiar to Windows Phone users.

A CarouselPage can only be populated with ContentPage instances, or ContentPage derivatives.

Populating a CarouselPage with a Page Collection

The following XAML code example shows a CarouselPage that displays three ContentPage instances:

<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="CarouselPageNavigation.MainPage">
    <ContentPage>
        <ContentPage.Padding>
            <OnPlatform x:TypeArguments="Thickness" iOS="0,40,0,0" Android="0,40,0,0" />
        </ContentPage.Padding>
        <StackLayout>
            <Label Text="Red" FontSize="Medium" HorizontalOptions="Center" />
            <BoxView Color="Red" WidthRequest="200" HeightRequest="200" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage>
    <ContentPage>
        ...
    </ContentPage>
    <ContentPage>
        ...
    </ContentPage>
</CarouselPage>

The following code example shows the equivalent UI in C#:

public class MainPageCS : CarouselPage
{
    public MainPageCS ()
    {
        var padding = new Thickness (0, Device.OnPlatform (40, 40, 0), 0, 0);
        var redContentPage = new ContentPage {
            Padding = padding,
            Content = new StackLayout {
                Children = {
                    new Label {
                        Text = "Red",
                        FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
                        HorizontalOptions = LayoutOptions.Center
                    },
                    new BoxView {
                        Color = Color.Red,
                        WidthRequest = 200,
                        HeightRequest = 200,
                        HorizontalOptions = LayoutOptions.Center,
                        VerticalOptions = LayoutOptions.CenterAndExpand
                    }
                }
            }
        };
        var greenContentPage = new ContentPage {
            Padding = padding,
            Content = new StackLayout {
                ...
            }
        };
        var blueContentPage = new ContentPage {
            Padding = padding,
            Content = new StackLayout {
                ...
            }
        };

        Children.Add (redContentPage);
        Children.Add (greenContentPage);
        Children.Add (blueContentPage);
    }
}

Each ContentPage simply displays a Label for a particular color and a BoxView of that color.

The CarouselPage does not support UI virtualization. Therefore, performance may be affected if the CarouselPagecontains too many child elements.

If a CarouselPage is embedded into the Detail page of a MasterDetailPage, the MasterDetailPage.IsGestureEnabledproperty should be set to false to prevent gesture conflicts between the CarouselPage and the MasterDetailPage.

Populating a CarouselPage with a Template

The following XAML code example shows a CarouselPage constructed by assigning a DataTemplate to the ItemTemplateproperty to return pages for objects in the collection:

<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
              xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
              x:Class="CarouselPageNavigation.MainPage">
    <CarouselPage.ItemTemplate>
        <DataTemplate>
            <ContentPage>
                <ContentPage.Padding>
                    <OnPlatform x:TypeArguments="Thickness" iOS="0,40,0,0" Android="0,40,0,0" />
                </ContentPage.Padding>
                <StackLayout>
                    <Label Text="{Binding Name}" FontSize="Medium" HorizontalOptions="Center" />
                    <BoxView Color="{Binding Color}" WidthRequest="200" HeightRequest="200" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
                </StackLayout>
            </ContentPage>
        </DataTemplate>
    </CarouselPage.ItemTemplate>
</CarouselPage>

The CarouselPage is populated with data by setting the ItemsSource property in the constructor for the code-behind file:

public MainPage ()
{
    ...
    ItemsSource = ColorsDataModel.All;
}

The following code example shows the equivalent CarouselPage created in C#:

public class MainPageCS : CarouselPage
{
    public MainPageCS ()
    {
        ItemTemplate = new DataTemplate (() => {
            var nameLabel = new Label {
                FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
                HorizontalOptions = LayoutOptions.Center
            };
            nameLabel.SetBinding (Label.TextProperty, "Name");

            var colorBoxView = new BoxView {
                WidthRequest = 200,
                HeightRequest = 200,
                HorizontalOptions = LayoutOptions.Center,
                VerticalOptions = LayoutOptions.CenterAndExpand
            };
            colorBoxView.SetBinding (BoxView.ColorProperty, "Color");

            return new ContentPage {
                Padding = new Thickness (0, Device.OnPlatform (40, 40, 0), 0, 0),
                Content = new StackLayout {
                    Children = {
                        nameLabel,
                        colorBoxView
                    }
                }
            };
        });

        ItemsSource = ColorsDataModel.All;
    }
}

Each ContentPage simply displays a Label for a particular color and a BoxView of that color.

The CarouselPage does not support UI virtualization. Therefore, performance may be affected if the CarouselPagecontains too many child elements.

If a CarouselPage is embedded into the Detail page of a MasterDetailPage, the MasterDetailPage.IsGestureEnabledproperty should be set to false to prevent gesture conflicts between the CarouselPage and the MasterDetailPage.

This section demonstrated how to use a CarouselPage to navigate through a collection of pages. The CarouselPage is a page that users can swipe from side to side to navigate through pages of content, like a gallery, and provides a navigation experience that feels natural and familiar to Windows Phone users.

MasterDetailPage

The Xamarin.Forms MasterDetailPage is a page that manages two pages of related information – a master page that presents items, and a detail page that presents details about items on the master page.

Navigating between related pages

The Xamarin.Forms MasterDetailPage is a page that manages two related pages of information – a master page that presents items, and a detail page that presents details about items on the master page. This article demonstrates how to use a MasterDetailPage and navigate between its pages of information.

Creating a MasterDetailPage

A MasterDetailPage contains Master and Detail properties that are both of type Page, which are used to get and set the master and detail pages respectively.

It's recommended that the master page of a MasterDetailPage should always be a ContentPage instance, and that the detail page should only be populated with TabbedPage, NavigationPage, and ContentPage instances. This will help to ensure a consistent user experience across all platforms.

The following XAML code example shows a MasterDetailPage that sets the Master and Detail properties:

<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                  xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
                  x:Class="MasterDetailPageNavigation.MainPage">
    <MasterDetailPage.Master>
        <local:MasterPage x:Name="masterPage" />
    </MasterDetailPage.Master>
    <MasterDetailPage.Detail>
        <NavigationPage>
            <x:Arguments>
                <local:ContactsPage />
            </x:Arguments>
        </NavigationPage>
    </MasterDetailPage.Detail>
</MasterDetailPage>

The following code example shows the equivalent MasterDetailPage created in C#:

public class MainPageCS : MasterDetailPage
{
    MasterPageCS masterPage;

    public MainPageCS ()
    {
        masterPage = new MasterPageCS ();
        Master = masterPage;
        Detail = new NavigationPage (new ContactsPageCS ());
        ...
    }
    ...
}

The MasterDetailPage.Master property is set to a ContentPage instance. The MasterDetailPage.Detail property is set to a NavigationPage containing a ContentPage instance.

Creating the Master Page

The following XAML code example shows the declaration of the MasterPage object, which is referenced through the MasterDetailPage.Master property:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MasterDetailPageNavigation.MasterPage"
             Padding="0,40,0,0"
             Icon="hamburger.png"
             Title="Personal Organiser">
    <ContentPage.Content>
        <StackLayout VerticalOptions="FillAndExpand">
            <ListView x:Name="listView" VerticalOptions="FillAndExpand" SeparatorVisibility="None">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ImageCell Text="{Binding Title}" ImageSource="{Binding IconSource}" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

The page consists of a ListView, where each item in the ListView is an ImageCell that displays an image and a title. The page has its Title and Icon properties set. The icon will appear on the detail page, provided that the detail page has a title bar. This must be enabled on iOS by wrapping the detail page instance in a NavigationPage instance.

The MasterDetailPage.Master page must have its Title property set, or an exception will occur.

The ListView instance is populated with data in the code-behind file, as shown in the following code example:

public partial class MasterPage : ContentPage
{
    public ListView ListView { get { return listView; } }

    public MasterPage ()
    {
        InitializeComponent ();

        var masterPageItems = new List<MasterPageItem> ();
        masterPageItems.Add (new MasterPageItem{
            Title = "Contacts",
            IconSource = "contacts.png",
            TargetType = typeof(ContactsPage)
        });
        masterPageItems.Add (new MasterPageItem{
            Title = "TodoList",
            IconSource = "todo.png",
            TargetType = typeof(TodoListPage)
        });
        masterPageItems.Add (new MasterPageItem{
            Title = "Reminders",
            IconSource = "reminders.png",
            TargetType = typeof(ReminderPage)
        });

        listView.ItemsSource = masterPageItems;
    }
}

A MasterPageItem collection is created, with each MasterPageItem defining Title, IconSource, and TargetType properties. The IconSource and Title property values are displayed by the ImageCell for each item in the ListView instance.

he following code example shows the equivalent page created in C#:

public class MasterPageCS : ContentPage
{
    public ListView ListView { get { return listView; } }

    ListView listView;

    public MasterPageCS ()
    {
        var masterPageItems = new List<MasterPageItem> ();
        masterPageItems.Add (new MasterPageItem {
            Title = "Contacts",
            IconSource = "contacts.png",
            TargetType = typeof(ContactsPageCS)
        });
        masterPageItems.Add (new MasterPageItem {
            Title = "TodoList",
            IconSource = "todo.png",
            TargetType = typeof(TodoListPageCS)
        });
        masterPageItems.Add (new MasterPageItem {
            Title = "Reminders",
            IconSource = "reminders.png",
            TargetType = typeof(ReminderPageCS)
        });

        listView = new ListView {
            ItemsSource = masterPageItems,
            ItemTemplate = new DataTemplate (() => {
                var imageCell = new ImageCell ();
                imageCell.SetBinding (TextCell.TextProperty, "Title");
                imageCell.SetBinding (ImageCell.ImageSourceProperty, "IconSource");
                return imageCell;
            }),
            VerticalOptions = LayoutOptions.FillAndExpand,
            SeparatorVisibility = SeparatorVisibility.None
        };

        Padding = new Thickness (0, 40, 0, 0);
        Icon = "hamburger.png";
        Title = "Personal Organiser";
        Content = new StackLayout {
            VerticalOptions = LayoutOptions.FillAndExpand,
            Children = {
                listView
            }
        };
    }
}

The following screenshots show the master page on each platform:

Creating and Displaying the Detail Page

The MasterPage instance contains a ListView property that exposes its ListView instance so that the MainPageMasterDetailPage instance can register an event-handler to handle the ItemSelected event. This enables the MainPageinstance to set the Detail property to the page that represents the selected ListView item. The following code example shows the event-handler:

public partial class MainPage : MasterDetailPage
{
    public MainPage ()
    {
        ...
        masterPage.ListView.ItemSelected += OnItemSelected;
    }

    void OnItemSelected (object sender, SelectedItemChangedEventArgs e)
    {
        var item = e.SelectedItem as MasterPageItem;
        if (item != null) {
            Detail = new NavigationPage ((Page)Activator.CreateInstance (item.TargetType));
            masterPage.ListView.SelectedItem = null;
            IsPresented = false;
        }
    }
}

The OnItemSelected method performs the following actions:

  • It retrieves the SelectedItem from the ListView instance, and provided that it's not null, sets the detail page to a new instance of the page type stored in the TargetType property of the MasterPageItem. The page type is wrapped in a NavigationPage instance in order to ensure that the icon referenced through the Icon property on the MasterPage is shown on the detail page in iOS.
  • The selected item in the ListView is set to null in order to ensure that none of the ListView items will be selected next time the MasterPage is presented.
  • The detail page is presented to the user by setting the MasterDetailPage.IsPresented property to false. This property controls whether the master or detail page is presented. It should be set to true to display the master page, and to false to display the detail page.

The following screenshots show the ContactPage detail page, which is shown after it's been selected on the master page:

Rather than using a MasterDetailPage on Windows Phone, a user interface class that provides an experience that is more consistent with the platform should ideally be used, such as CarouselPage.

Controlling the Detail Page Display Behavior

How the MasterDetailPage manages the master and detail pages depends on whether the application is running on a phone or tablet, the orientation of the device, and the value of the MasterBehavior property. This property determines how the detail page will be displayed. It's possible values are:

  • Default – The pages are displayed using the platform default.
  • Popover – The detail page covers, or partially covers the master page.
  • Split – The master page is displayed on the left and the detail page is on the right.
  • SplitOnLandscape – A split screen is used when the device is in landscape orientation.
  • SplitOnPortrait – A split screen is used when the device is in portrait orientation.

The following XAML code example demonstrates how to set the MasterBehavior property on a MasterDetailPage:

<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
                  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                  x:Class="MasterDetailPageNavigation.MainPage"
                  MasterBehavior="Popover">
  ...
</MasterDetailPage>

The following code example shows the equivalent MasterDetailPage created in C#:

public class MainPageCS : MasterDetailPage
{
    MasterPageCS masterPage;

    public MainPageCS ()
    {
        MasterBehavior = MasterBehavior.Popover;
        ...
    }
}

However, the value of the MasterDetailPage property only affects applications running on tablets. Applications running on phones always have the Popover behavior.

This section demonstrated how to use a MasterDetailPage and navigate between its pages of information. The Xamarin.Forms MasterDetailPage is a page that manages two pages of related information – a master page that presents items, and a detail page that presents details about items on the master page.

Modal Pages

Xamarin.Forms also provides support for modal pages. A modal page encourages users to complete a self-contained task that cannot be navigated away from until the task is completed or cancelled.

Navigating to modal pages

Xamarin.Forms provides support for modal pages. A modal page encourages users to complete a self-contained task that cannot be navigated away from until the task is completed or cancelled. This article demonstrates how to navigate to modal pages.

This article discusses the following topics:

  • Performing navigation – pushing pages to the modal stack, popping pages from the modal stack, disabling the back button, and animating page transitions.
  • Passing data when navigating – passing data through a page constructor, and through a BindingContext.

A modal page can be any of the Page types supported by Xamarin.Forms. To display a modal page the application will push it onto the navigation stack, where it will become the active page, as shown in the following diagram:

To return to the previous page the application will pop the current page from the navigation stack, and the new topmost page becomes the active page, as shown in the following diagram:

Performing Navigation

Modal navigation methods are exposed by the Navigation property on any Page derived types. These methods provide the ability to push modal pages onto the navigation stack, and pop modal pages from the navigation stack.

The Navigation property also exposes a ModalStack property from which the modal pages in the navigation stack can be obtained. However, there is no concept of performing modal stack manipulation, or popping to the root page in modal navigation. This is because these operations are not universally supported on the underlying platforms.

A NavigationPage instance is not required for performing modal page navigation.

Pushing Pages to the Modal Stack

To navigate to the ModalPage it is necessary to invoke the PushModalAsync method on the Navigation property of the current page, as demonstrated in the following code example:

async void OnItemSelected (object sender, SelectedItemChangedEventArgs e)
{
  if (listView.SelectedItem != null) {
    var detailPage = new DetailPage ();
    ...
    await Navigation.PushModalAsync (detailPage);
  }
}

This causes the ModalPage instance to be pushed onto the navigation stack, where it becomes the active page, provided that an item has been selected in the ListView on the MainPage instance. The ModalPage instance is shown in the following screenshots:

When PushModalAsync is invoked, the following events occur:

  • The page calling PushModalAsync has its OnDisappearing override invoked, provided that the underlying platform isn't Android.
  • The page being navigated to has its OnAppearing override invoked.
  • The PushAsync task completes.

Calls to the OnDisappearing and OnAppearing overrides cannot be treated as guaranteed indications of page navigation. For example, on iOS, the OnDisappearing override is called on the active page when the application terminates.

Popping Pages from the Modal Stack

The active page can be popped from the navigation stack by pressing the Back button on the device, regardless of whether this is a physical button on the device or an on-screen button.

To programmatically return to the original page, the ModalPage instance must invoke the PopModalAsync method, as demonstrated in the following code example:

async void OnDismissButtonClicked (object sender, EventArgs args)
{
  await Navigation.PopModalAsync ();
}

This causes the ModalPage instance to be removed from the navigation stack, with the new topmost page becoming the active page. When PopModalAsync is invoked, the following events occur:

  • The page calling PopAsync has its OnDisappearing override invoked.
  • The page being returned to has its OnAppearing override invoked, provided that the underlying platform isn't Android.
  • The PopModalAsync task returns.

Disabling the Back Button

On Android and Windows Phone, the user can always return to the previous page by pressing the standard Back button on the device. If the modal page requires the user to complete a self-contained task before leaving the page, the application must disable the Back button. This can be accomplished by overriding the Page.OnBackButtonPressed method on the modal page.

Animating Page Transitions

The Navigation property of each page also provides overridden push and pop methods that include a boolean parameter that controls whether to display a page animation during navigation, as shown in the following code example:

async void OnNextPageButtonClicked (object sender, EventArgs e)
{
  // Page appearance not animated
  await Navigation.PushModalAsync (new DetailPage (), false);
}

async void OnDismissButtonClicked (object sender, EventArgs args)
{
  // Page appearance not animated
  await Navigation.PopModalAsync (false);
}

Setting the boolean parameter to false disables the page-transition animation, while setting the parameter to true enables the page-transition animation, provided that it is supported by the underlying platform. However, the push and pop methods that lack this parameter enable the animation by default.

Passing Data when Navigating

Sometimes it's necessary for a page to pass data to another page during navigation. Two techniques for accomplishing this are by passing data through a page constructor, and by setting the new page's BindingContext to the data. Each will now be discussed in turn.

Passing Data through a Page Constructor

The simplest technique for passing data to another page during navigation is through a page constructor parameter, which is shown in the following code example:

public App ()
{
  MainPage = new MainPage (DateTime.Now.ToString ("u")));
}

This code creates a MainPage instance, passing in the current date and time in ISO8601 format.

The MainPage instance receives the data through a constructor parameter, as shown in the following code example:

public MainPage (string date)
{
  InitializeComponent ();
  dateLabel.Text = date;
}

The data is then displayed on the page by setting the Label.Text property.

Passing Data through a BindingContext

An alternative approach for passing data to another page during navigation is by setting the new page's BindingContext to the data, as shown in the following code example:

async void OnItemSelected (object sender, SelectedItemChangedEventArgs e)
{
  if (listView.SelectedItem != null) {
    var detailPage = new DetailPage ();
    detailPage.BindingContext = e.SelectedItem as Contact;
    listView.SelectedItem = null;
    await Navigation.PushModalAsync (detailPage);
  }
}

This code sets the BindingContext of the DetailPage instance to the Contact instance, and then navigates to the DetailPage.

The DetailPage then uses data binding to display the Contact instance data, as shown in the following XAML code example:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ModalNavigation.DetailPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness" iOS="0,40,0,0" />
    </ContentPage.Padding>
    <ContentPage.Content>
        <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
            <StackLayout Orientation="Horizontal">
                <Label Text="Name:" FontSize="Medium" HorizontalOptions="FillAndExpand" />
                <Label Text="{Binding Name}" FontSize="Medium" FontAttributes="Bold" />
            </StackLayout>
              ...
            <Button x:Name="dismissButton" Text="Dismiss" Clicked="OnDismissButtonClicked" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

The following code example shows how the data binding can be accomplished in C#:

public class DetailPageCS : ContentPage
{
  public DetailPageCS ()
  {
    var nameLabel = new Label {
      FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
      FontAttributes = FontAttributes.Bold
    };
    nameLabel.SetBinding (Label.TextProperty, "Name");
    ...
    var dismissButton = new Button { Text = "Dismiss" };
    dismissButton.Clicked += OnDismissButtonClicked;

    Padding = new Thickness (0, Device.OnPlatform (20, 0, 0), 0, 0);
    Content = new StackLayout {
      HorizontalOptions = LayoutOptions.Center,
      VerticalOptions = LayoutOptions.Center,
      Children = {
        new StackLayout {
          Orientation = StackOrientation.Horizontal,
          Children = {
            new Label{ Text = "Name:", FontSize = Device.GetNamedSize (NamedSize.Medium, typeof(Label)), HorizontalOptions = LayoutOptions.FillAndExpand },
            nameLabel
          }
        },
        ...
        dismissButton
      }
    };
  }

  async void OnDismissButtonClicked (object sender, EventArgs args)
  {
    await Navigation.PopModalAsync ();
  }
}

The data is then displayed on the page by a series of Label controls.

This section demonstrated how to navigate to modal pages. A modal page encourages users to complete a self-contained task that cannot be navigated away from until the task is completed or cancelled.

Displaying Pop-Ups

Xamarin.Forms provides two pop-up-like user interface elements: an alert and an action sheet. These interface elements can be used to ask users simple questions and to guide users through tasks.

Displaying alerts and guiding users through tasks

Xamarin.Forms provides two pop-up-like user interface elements: an alert and an action sheet. This article demonstrates using the alert and action sheet APIs to ask users simple questions and to guide users through tasks.

Displaying an alert or asking a user to make a choice is a common UI task. Xamarin.Forms has two methods on the Page class for interacting with the user via a pop-up: DisplayAlert and DisplayActionSheet. They are rendered with appropriate native controls on each platform.

Displaying an Alert

All Xamarin.Forms-supported platforms have a modal pop-up to alert the user or ask simple questions of them. To display these alerts in Xamarin.Forms, use the DisplayAlert method on any Page. The following line of code shows a simple message to the user:

DisplayAlert ("Alert", "You have been alerted", "OK");

This example does not collect information from the user. The alert displays modally and once dismissed the user continues interacting with the application.

The DisplayAlert method can also be used to capture a user's response by presenting two buttons and returning a boolean. To get a response from an alert, supply text for both buttons and await the method. After the user selects one of the options the answer will be returned to your code. Note the async and await keywords in the sample code below:

async void OnAlertYesNoClicked (object sender, EventArgs e)
{
  var answer = await DisplayAlert ("Question?", "Would you like to play a game", "Yes", "No");
  Debug.WriteLine ("Answer: " + answer);
}

Guiding Users Through Tasks

The UIActionSheet is a common UI element in iOS. The Xamarin.Forms DisplayActionSheet method lets you include this control in cross-platforms apps, rendering native alternatives in Android and Windows Phone.

To display an action sheet, await DisplayActionSheet in any Page, passing the message and button labels as strings. The method returns the string label of the button that was clicked by the user. A simple example is shown here:

async void OnActionSheetSimpleClicked (object sender, EventArgs e)
{
  var action = await DisplayActionSheet ("ActionSheet: Send to?", "Cancel", null, "Email", "Twitter", "Facebook");
  Debug.WriteLine ("Action: " + action);
}

The destroy button is rendered differently than the others, and can be left null or specified as the third string parameter. The following example uses the destroy button:

This section demonstrated using the alert and action sheet APIs to ask users simple questions and to guide users through tasks. Xamarin.Forms has two methods on the Page class for interacting with the user via a pop-up: DisplayAlert and DisplayActionSheet, and they are both rendered with appropriate native controls on each platform.

No Comments

Add a Comment

As it will appear on the website

Not displayed

Your website