Once you created Xamarin.Forms Shell App, by adapting Blank template or by reducing shell template to bare minimum, you might also need to know how to navigate to content page which is not defined in AppShell.xaml.
Here are steps on how to achieve that:
Add New Page
Let's add new page called OtherView (under the Views directory) which will be content page we will navigate from MainView.
Change the Label text in created OtherView.xaml so that it's clear that it's different page when we navigate to it:
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Other Page!"
VerticalOptions="CenterAndExpand" />
Register Route to New Page
Open AppShell.xaml.cs and change it like this:
using Xamarin.Forms;
using XamarinNavigation.Views;
namespace XamarinNavigation
{
public partial class AppShell : Shell
{
public AppShell()
{
InitializeComponent();
RegisterRoutes();
}
private void RegisterRoutes()
{
Routing.RegisterRoute("other", typeof(OtherView));
}
}
}
What we added is private method called RegisterRoutes in constructor of AppShell. Its implementation contains registration of a global route to our new page called OtherView.
For more information, see:
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation=
Add a Button for Navigation
Add a Button in MainView.xaml.
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand" />
<Button Text="Press me!" />
</StackLayout>
When we press this button now, nothing happens. This is expected, because we didn't bind it to any command yet.
Let's do that in next step.
Add MainViewModel
Create new class called MainViewModel in ViewModels directory.
namespace XamarinNavigation.ViewModels
{
public class MainViewModel : BaseViewModel
{
}
}
This new class derives from BaseViewModel class, so that we don't have to implement again INotifyPropertyChanged interface again.
Join View and ViewModel
There are multiple ways on how to join View and ViewModel to work together.
Here is one way how to do that:
Adapt MainView.xaml. Add
xmlns:vm="clr-namespace:XamarinNavigation.ViewModels"
to <ContentPage> declaration so that we have reference to ViewModels directory (namespace).
Note, that vm is just name for the declared namespace, you can name it as you like (e.g. viewModels).
and add BindingContext like this:
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
the result MainView content page looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
x:Class="XamarinNavigation.Views.MainView"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:XamarinNavigation.ViewModels"
mc:Ignorable="d">
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand" />
<Button Text="Press me!" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
When we press the button now, it still doesn't do anything, but now we have MainViewModel that we can use for creating a Command for binding the button.
Add Command to Button
Change a button in our MainView.xaml like this:
<Button Command="{Binding PressMeCommand}" Text="Press me!" />
We defined Command property on button and bind it to property called PressMeCommand on our MainViewModel view model.
This property doesn't exist yet on view model, so let's create it:
using Xamarin.Forms;
namespace XamarinNavigation.ViewModels
{
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
PressMeCommand = new Command(PressMe);
}
public Command PressMeCommand { get; }
private void PressMe(object obj)
{
}
}
}
The Command implementation comes from defined using Xamarin.Forms.
With this implementation the button is always enabled and when button is pressed, PressMe method is called.
Parameter object obj is optionally used to bind from xaml to pass additional information.
Currently it will be null.
Convension says that we usually name our command properties with suffix Command (e.g. SaveComand, OpenCommand, TapCommand,...)
Navigate to Other Page
Now, when we have implemented a button with MVVM (Model-View-ViewModel) binded to Command and registered OtherView content page in our AppShell.xaml.cs, let's implement actual code used to navigate to this page:
public class MainViewModel : BaseViewModel
{
public MainViewModel()
{
PressMeCommand = new Command(async obj => await PressMe(obj));
}
public Command PressMeCommand { get; }
private async Task PressMe(object obj)
{
await Shell.Current.GoToAsync("other");
}
}
For more information, see this link:
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation
Let's explain little bit what's going on there:
There are couple of important changes:
- Implemented
PressMe(object obj)method:
await Shell.Current.GoToAsync("other");
"other" parameter to GoToAsync method represents globally defined route for the OtherView page.
- Changed return value of
PressMe(object obj)method toasync Task:
private async Task PressMe(object obj)
(Very) simply said, if you awaits some async method (like we did with await Shell.Current.GoToAsync("other");)
you need to change declaration of containing method to async and change return type in case of void to Task.
What it means is that actual navigation to other page will be performed in different thread.
For more information about asynchronous programming in C# see link:
https://docs.microsoft.com/en-us/dotnet/csharp/async
- The way how
PressMeCommandis created is changed and instead ofnew Command(PressMe)there isnew Command(async obj => await PressMe(obj)). Reason for that is that we changedvoidtoTaskand addedasync, so instead of passing delegate parameter we need to pass async lambda. Note, that from asynchronous programming point of view, it's still fire and forget.
Now, if we build and start the application here is the navigation in action:
MainView:
When you press PRESS ME! button located at the bottom of the page, you will navigate to other view:
OtherView:
Notice that back buttom is automatically added at the top left corner and it can be used to navigate back to the MainView.




Top comments (0)