Как реализовать навигацию между страницами в Xamarin.Forms?

В Xamarin.Forms навигация между страницами — это процесс перемещения пользователя от одного экрана приложения (Page) к другому. Фреймворк предоставляет несколько подходов к навигации, в зависимости от используемой архитектуры и типа страниц. Основные механизмы:

  • NavigationPage — стековая (иерархическая) навигация, классический способ.

  • TabbedPage — навигация по вкладкам.

  • FlyoutPage (ранее MasterDetailPage) — навигация через боковое меню.

  • Shell — современный способ с маршрутизацией и интеграцией различных типов страниц.

  • Modal navigation — модальные страницы (всплывающие/изолированные).

1. Навигация через NavigationPage (иерархическая навигация)

NavigationPage — это контейнер, реализующий стековую структуру переходов между страницами. Каждая новая страница добавляется в стек методом PushAsync(), а возврат назад осуществляется с помощью PopAsync().

Создание NavigationPage

MainPage = new NavigationPage(new HomePage());

Переход на новую страницу

await Navigation.PushAsync(new DetailsPage());  

Возврат на предыдущую страницу

await Navigation.PopAsync();

Возврат к корневой странице

await Navigation.PopToRootAsync();

Пример кнопки в XAML

<Button Text="Открыть детали" Command="{Binding OpenDetailsCommand}" />

ViewModel

public ICommand OpenDetailsCommand => new Command(async () =>
{
await Application.Current.MainPage.Navigation.PushAsync(new DetailsPage());
});

2. Модальная навигация (Modal Navigation)

Модальные страницы отображаются поверх всего интерфейса, не влияя на стек NavigationPage. Это может быть полезно для экранов входа, предупреждений, диалогов и т.д.

Открытие модальной страницы

await Navigation.PushModalAsync(new LoginPage());

Закрытие модальной страницы

await Navigation.PopModalAsync();

Модальные страницы не добавляются в стек обычной навигации. Они создаются и закрываются независимо.

3. Навигация с TabbedPage (вкладки)

TabbedPage содержит несколько дочерних страниц и позволяет переключаться между ними по вкладкам. Навигация реализуется автоматически при выборе вкладки.

Пример создания TabbedPage

MainPage = new TabbedPage
{
Children =
{
new HomePage { Title = "Домой" },
new ProfilePage { Title = "Профиль" },
new SettingsPage { Title = "Настройки" }
}
};

Выбор вкладки программно

var tabbedPage = Application.Current.MainPage as TabbedPage;
tabbedPage.CurrentPage = tabbedPage.Children\[1\]; // выбрать вторую вкладку

4. Навигация с FlyoutPage (MasterDetailPage)

FlyoutPage (ранее MasterDetailPage) реализует навигацию через боковое меню, которое открывается свайпом или нажатием на иконку.

Пример структуры

public class AppShell : FlyoutPage
{
public AppShell()
{
Flyout = new MenuPage(); // меню
Detail = new NavigationPage(new HomePage()); // содержимое
}
}

Переход на страницу из меню

((FlyoutPage)Application.Current.MainPage).Detail = new NavigationPage(new ProfilePage());
((FlyoutPage)Application.Current.MainPage).IsPresented = false; // закрыть меню

5. Навигация через Shell

Shell — современная и унифицированная система навигации в Xamarin.Forms, доступная начиная с версии 4.0. Позволяет использовать маршруты, вкладки, боковое меню, глубокие ссылки и упрощённый синтаксис переходов между страницами.

Создание AppShell (XAML)

<Shell xmlns="http://xamarin.com/schemas/2014/forms"
x:Class="MyApp.AppShell">
&lt;FlyoutItem Title="Главная"&gt;
&lt;ShellContent Route="home" ContentTemplate="{DataTemplate local:HomePage}" /&gt;
&lt;/FlyoutItem&gt;
&lt;FlyoutItem Title="Профиль"&gt;
&lt;ShellContent Route="profile" ContentTemplate="{DataTemplate local:ProfilePage}" /&gt;
&lt;/FlyoutItem&gt;
&lt;/Shell&gt;

Навигация по маршрутам

await Shell.Current.GoToAsync("profile");

С параметрами

await Shell.Current.GoToAsync($"details?id=42");

Регистрация маршрутов в C#

Routing.RegisterRoute("details", typeof(DetailPage));

Переход к странице с маршрутом

await Shell.Current.GoToAsync("details");

6. Навигация с параметрами (Shell + QueryProperty)

Чтобы передать параметры в страницу при навигации в Shell, используется механизм QueryProperty.

Пример приёма параметров в целевой странице

\[QueryProperty(nameof(ItemId), "id")\]
public partial class DetailPage : ContentPage
{
public string ItemId
{
set
{
// Логика по загрузке данных по ID
}
}
public DetailPage()
{
InitializeComponent();
}
}

Навигация с передачей параметров

await Shell.Current.GoToAsync("details?id=123");

7. Навигация с использованием MVVM

В архитектуре MVVM принято выносить навигационную логику из View в ViewModel, используя команды и сервисы.

Создание интерфейса INavigationService

public interface INavigationService
{
Task NavigateToAsync(Page page);
Task NavigateBackAsync();
}

Пример ViewModel с навигацией

public class MainViewModel
{
public ICommand GoToDetailsCommand { get; }
public MainViewModel()
{
GoToDetailsCommand = new Command(async () =>
{
await Application.Current.MainPage.Navigation.PushAsync(new DetailPage());
});
}
}

8. Навигация внутри StackLayout/ScrollView (без перехода между страницами)

Иногда переключение интерфейса происходит без перехода между страницами, а путём скрытия/отображения различных элементов внутри одной страницы.

Пример в XAML:

&lt;StackLayout x:Name="LoginLayout" IsVisible="True"&gt;
&lt;Entry Placeholder="Логин" /&gt;
&lt;Entry Placeholder="Пароль" /&gt;
&lt;Button Text="Войти" Clicked="OnLoginClicked" /&gt;
&lt;/StackLayout&gt;
&lt;StackLayout x:Name="ProfileLayout" IsVisible="False"&gt;
&lt;Label Text="Добро пожаловать!" /&gt;
&lt;/StackLayout&gt;

И в коде:

private void OnLoginClicked(object sender, EventArgs e)
{
LoginLayout.IsVisible = false;
ProfileLayout.IsVisible = true;
}

9. Работа с Navigation Stack

Получение текущей страницы:

var currentPage = Navigation.NavigationStack.Last();

Просмотр всего стека:

var pages = Navigation.NavigationStack;

Удаление страниц из стека:

Navigation.RemovePage(Navigation.NavigationStack\[1\]);

10. Общие рекомендации

  • Используйте NavigationPage для простых вложенных переходов (например, список → детали).

  • Применяйте Shell для сложных и многоуровневых приложений.

  • Храните навигационную логику в ViewModel через команды или навигационные сервисы.

  • Избегайте хранения состояний в страницах — лучше использовать ViewModel и DI.

  • Для переходов, требующих подтверждения, используйте DisplayAlert и модальные страницы.

  • Навигация между платформами (например, Android и iOS) работает одинаково, если используется общий код Xamarin.Forms.

Система навигации в Xamarin.Forms — мощная и гибкая, позволяющая реализовать как простые переходы между экранами, так и сложную маршрутизированную архитектуру с Shell, вкладками, боковыми меню и глубокими ссылками. Разработчик сам выбирает подход в зависимости от сложности интерфейса и предпочтительной архитектурной модели.