Mobiele apps programmeren met Xamarin – Navigatie – MasterDetail

print

Inhoud


Wat vooraf ging


Wat is MasterDetail?

Navigating between related pages

Een MasterDetailpage bestaat uit een Master page die een lijst bevat met mogelijke items/acties die elk naar een Detail page leiden die details over dat item bevat.

De Master Page bevat een navigation bar dat een knop bevat die de lijst zichtbaar maakt die kan gebruikt worden om naar de detail pages te navigeren.

A MasterDetailPage is designed to be a root page, and using it as a child page in other page types could result in unexpected and inconsistent behavior. In addition, 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.


Uitgewerkt voorbeeld

Visual Studio 2017 komt ook met een template voor MasterDetail maar deze template genereerde bij mij een fout. Omdat dit een complexere setup is dan de andere navigatiepagina’s ga ik hier vertrekken vanuit een voorbeeldproject in plaats van alles zelf vanaf de grond op te bouwen.

Het project komt met een uitgewerkt voorbeeld zowel in XAML als in C#. Ik ga me hier focussen op de XAML-versie.

Tevens zijn er een aantal afbeeldingen toegevoegd die gebruikt worden als icoontjes in de keuzelijst van de Master page.

De applicatie ziet er als volgt uit:

Laat ons nu de verschillende bestanden in detail bekijken.

MasterPageItem.cs

Dit is een klasse die aangemaakt is om gegevens van de items die in de lijst op de Master page voorkomen bij te houden. Er wordt een titel, icoontje en het type bijgehouden.

using System;

namespace MasterDetailPageNavigation
{
	public class MasterPageItem
	{
		public string Title { get; set; }
		public string IconSource { get; set; }
		public Type TargetType { get; set; }
	}
}

App.cs

Zoals u reeds weet wordt in App.cs bepaald met welke pagina uw applicatie opstart.

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[assembly:XamlCompilation(XamlCompilationOptions.Compile)]
namespace MasterDetailPageNavigation
{
	public class App : Application
	{
		public App ()
		{
			MainPage = new MasterDetailPageNavigation.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
		}
	}
}

MainPage.xaml

De MainPage.xaml is de pagina die opgestart wordt. Zij bevat de 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" 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>

Merk op dat de pagina van het type MasterDetailPage is.
Voeg de namespace van het huidige project toe. Ze krijgt hier de naam local.

xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"

De MasterDetailPage bevat een Master die een verwijzing naar de Master bevat.

    <MasterDetailPage.Master>
  	    <local:MasterPage x:Name="masterPage" />
    </MasterDetailPage.Master>

De MasterDetailPage bevat een Detail die een verwijzing naar een Detail bevat. In dit geval de ContactsPage.

    <MasterDetailPage.Detail>
	    <NavigationPage>
		    <x:Arguments>
			    <local:ContactsPage />
		    </x:Arguments>
	    </NavigationPage>
    </MasterDetailPage.Detail>

MainPage.xaml.cs

De code-behind van deze pagina is als volgt.

using System;
using Xamarin.Forms;

namespace MasterDetailPageNavigation
{
    public partial class MainPage : MasterDetailPage
    {
        public MainPage()
        {
            InitializeComponent();

            masterPage.ListView.ItemSelected += OnItemSelected;

            if (Device.RuntimePlatform == Device.UWP)
            {
                MasterBehavior = MasterBehavior.Popover;
            }
        }

        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;
            }
        }
    }
}

De uitleg zal misschien maar volledig duidelijk worden nadat de masterPage is besproken maar weet dat deze masterPage een keuzelijst (ListView) bevat met de detailpagina’s die kunnen worden aangeklikt.

Binnen deze ListView moet u items kunnen selecteren. Er wordt dus een event toegevoegd.

masterPage.ListView.ItemSelected += OnItemSelected;

Binnen deze event wordt eerst gekeken welk item er geselecteerd is en of er wel een item geselecteerd is.

        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;
            }
        }

Indien een item geselecteerd is wordt het item.TargetType, die een verwijzing naar de gewenste pagina bevat (zie zo dadelijk), gebruikt om de gewenste pagina aan het Detail-luik toe te voegen. Dit gebeurt via volgende, wat complexe, code.


Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));

Vervolgens wordt de selectie ongedaan gemaakt.


masterPage.ListView.SelectedItem = null;

De code IsPresented = false; bepaalt of het Master-luik met de lijst in beeld moet blijven of niet.

De eigenschap MasterBehavior wordt ook ingesteld. De mogelijke waarden zijn:

  • Default – De standaard van het platform wordt gebruikt om de pagina’s weer te geven.
  • Popover – De detail page overdekt geheel of gedeeltelijk de master page.
  • Split – De master page komt links en de detail page rechts.
  • SplitOnLandscape – Een split screen wordt gebruikt wanneer de device in landscape orientation is.
  • SplitOnPortrait – Een split screen wordt gebruikt wanneer de device in portrait orientation is.

Deze code gebruikt de Default, tenzij op UWP dan wordt Popover gebruikt.

if (Device.RuntimePlatform == Device.UWP)
{
     MasterBehavior = MasterBehavior.Popover;
}

MasterPage.xaml

De MasterPage bevat de keuzelijst (ListView) met de detailpagina’s die kunnen worden aangeklikt. Deze pagina is een gewone ContentPage.

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="using:MasterDetailPageNavigation" x:Class="MasterDetailPageNavigation.MasterPage" Padding="0,40,0,0" Icon="hamburger.png" Title="Personal Organiser">
    <StackLayout>
        <ListView x:Name="listView">
           <ListView.ItemsSource>
                <x:Array Type="{x:Type local:MasterPageItem}">
                    <local:MasterPageItem Title="Contacts" IconSource="contacts.png" TargetType="{x:Type local:ContactsPage}" />
                    <local:MasterPageItem Title="TodoList" IconSource="todo.png" TargetType="{x:Type local:TodoListPage}" />
                    <local:MasterPageItem Title="Reminders" IconSource="reminders.png" TargetType="{x:Type local:ReminderPage}" />
                </x:Array>
            </ListView.ItemsSource>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid Padding="5,10">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="30"/>
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <Image Source="{Binding IconSource}" />
                            <Label Grid.Column="1" Text="{Binding Title}" />
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

Voeg de namespace van het huidige project toe. Ze krijgt hier de naam local.

xmlns:local="using:MasterDetailPageNavigation"

De ListView bestaat uit een ListView.ItemsSource en uit een ListView.ItemTemplate.

De ListView.ItemsSource gebruikt de aangemaakte klasse MasterPageItem om de items toe te voegen als een array van deze klasse x:Array Type="{x:Type local:MasterPageItem}". Elk toegevoegd item heeft een Title, IconSource en TargetType zoals bepaald i de klasse MasterPageItem. TargetType bevat een verwijzing naar de eigenlijke pagina TargetType="{x:Type local:ContactsPage}

<ListView.ItemsSource>
    <x:Array Type="{x:Type local:MasterPageItem}">
        <local:MasterPageItem Title="Contacts" IconSource="contacts.png" TargetType="{x:Type local:ContactsPage}" />
        <local:MasterPageItem Title="TodoList" IconSource="todo.png" TargetType="{x:Type local:TodoListPage}" />
        <local:MasterPageItem Title="Reminders" IconSource="reminders.png" TargetType="{x:Type local:ReminderPage}" />
    </x:Array>
</ListView.ItemsSource>

De ListView.ItemTemplate bepaalt de weergave op basis van een DataTemplate die een ViewCell bevat die op zijn beurt een Grid bevat om het icoontje Image Source="{Binding IconSource}" en de titel Label Grid.Column="1" Text="{Binding Title}" weer te geven binnen de lijst.

<ListView.ItemTemplate>
    <DataTemplate>
        <ViewCell>
            <Grid Padding="5,10">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="30"/>
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Image Source="{Binding IconSource}" />
                <Label Grid.Column="1" Text="{Binding Title}" />
            </Grid>
        </ViewCell>
    </DataTemplate>
</ListView.ItemTemplate>

Herinner u dat het aanklikken van het item reeds uitgewerkt is op het niveau van de MainPage.

MasterPage.xaml.cs

Vergeet niet in de code-behind van deze pagina de ListView publiekelijke te maken zodat die toegankelijk is vanuit de MainPage.

using Xamarin.Forms;

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

        public MasterPage()
        {
            InitializeComponent();
        }
    }
}

Detail pages

Complex tot nu toe? Ja, redelijk, dus bent u wellicht ook tevreden dat alle detailpagina’s gewone pagina’s zijn zonder meer. Bekijk de TodoListPage.

<?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="MasterDetailPageNavigation.TodoListPage" Title="TodoList Page">
	<ContentPage.Content>
		<StackLayout>
			<Label Text="Todo list data goes here" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" />
		</StackLayout>
	</ContentPage.Content>
</ContentPage>

en de code-behind:

using Xamarin.Forms;

namespace MasterDetailPageNavigation
{
	public partial class TodoListPage : ContentPage
	{
		public TodoListPage ()
		{
			InitializeComponent ();
		}
	}
}

Behandelde Basiscompetenties uit de module ICT Programmeren – Integratie externe functionaliteiten

  • IC BC017 – kan ICT veilig en duurzaam gebruiken
  • IC BC256 – kan diverse elementen tot een nieuw betekenisvol geheel samenstellen
  • IC BC288 – kan ICT-problemen oplossen

Geef een reactie

  • Abonneer je op deze website d.m.v. e-mail

    Voer je e-mailadres in om je in te schrijven op deze website en e-mailmeldingen te ontvangen van nieuwe berichten.