# Sextant
**Repository Path**: mirrors_reactiveui/Sextant
## Basic Information
- **Project Name**: Sextant
- **Description**: A ReactiveUI navigation library for Xamarin.Forms
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-09-25
- **Last Updated**: 2026-01-04
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## Sextant
[](https://www.nuget.org/packages/sextant)  [](https://codecov.io/gh/reactiveui/sextant)
[ ](https://www.nuget.org/packages/sextant) [](https://reactiveui.net/slack)

## A ReactiveUI view model based navigation library
Sextant provides a simple, reactive, view model first navigation service for ReactiveUI applications. It originated from ideas in Kent Boogaart's “Custom routing in ReactiveUI” and has evolved to support modern platforms and the latest ReactiveUI/Splat patterns.
Sextant focuses on:
- ViewModel-first navigation with reactive APIs (IObservable)
- Lifecycle hooks for parameterized navigation (INavigable)
- Uniform abstractions across platforms with pluggable IView/IViewLocator
## Packages
Install the packages into your app and platform projects, depending on target UI stack.
- Core (required): Sextant
- .NET MAUI: Sextant.Maui (NavigationView + DI helpers)
- Avalonia: Sextant.Avalonia (NavigationView + DI helpers)
- Optional: Sextant.Plugins.Popup (MAUI, Mopups based modal plugin)
Minimum platform versions follow ReactiveUI platform minimums: https://reactiveui.net/docs/getting-started/minimum-versions#platform-minimums
## Bootstrapping with AppLocator (and AppBuilder)
ReactiveUI/Splat provide AppLocator (and AppBuilder) to configure dependency resolution for your app. Sextant integrates with AppLocator and auto-initializes when the resolver is ready.
At app startup, register your navigation view, view models, and view locator, then push the initial page.
### .NET MAUI quick start
- Ensure you’ve added ReactiveUI.Maui and Sextant.Maui.
- Register views and services using AppLocator.
- Set MainPage to the registered NavigationView.
Example (in App constructor or after DI setup):
```csharp
using ReactiveUI;
using ReactiveUI.Maui;
using Sextant;
using Sextant.Maui;
using Splat;
// Register all navigation components
AppLocator.CurrentMutable
// IViewLocator should be registered in your app; many apps use ReactiveUI.ViewLocator.Current
.RegisterConstant(ReactiveUI.ViewLocator.Current, typeof(IViewLocator))
.RegisterNavigationView() // Sextant.Maui NavigationView
.RegisterViewModelFactory(() => new DefaultViewModelFactory())
.RegisterParameterViewStackService()
// Views and VMs for navigation
.RegisterViewForNavigation(() => new HomeView(), () => new HomeViewModel())
.RegisterViewForNavigation(() => new DetailsView(), () => new DetailsViewModel());
// Push initial page
AppLocator.Current
.GetService()
.PushPage(resetStack: true, animate: false)
.Subscribe();
// Hook MAUI MainPage to Sextant NavigationView
MainPage = AppLocator.Current.GetNavigationView();
```
Notes
- If you don’t pass parameters, IViewStackService is sufficient. If you pass parameters or use INavigable lifecycle, prefer IParameterViewStackService.
- Sextant.Maui exposes GetNavigationView() to fetch the registered NavigationView.
### Avalonia quick start
Register navigation and show a window containing the NavigationView.
```csharp
using Avalonia;
using Avalonia.Controls;
using ReactiveUI;
using Sextant;
using Sextant.Avalonia;
using Splat;
public static class Program
{
[STAThread]
public static void Main(string[] args)
{
BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
}
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
.UseReactiveUI();
}
public class App : Application
{
public override void OnFrameworkInitializationCompleted()
{
// DI registrations
AppLocator.CurrentMutable
.RegisterConstant(ReactiveUI.ViewLocator.Current, typeof(IViewLocator))
.RegisterNavigationView(() => new Sextant.Avalonia.NavigationView())
.RegisterViewModelFactory(() => new DefaultViewModelFactory())
.RegisterViewForNavigation(() => new HomeView(), () => new HomeViewModel());
var viewStack = AppLocator.Current.GetService()!;
viewStack.PushPage(resetStack: true).Subscribe();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new Window { Content = AppLocator.Current.GetNavigationView() };
}
base.OnFrameworkInitializationCompleted();
}
}
```
## Using the navigation services
Sextant provides two main services:
- IViewStackService – view model first navigation
- IParameterViewStackService – navigation with parameters and lifecycle
Common methods (both services)
- IObservable PushPage(string? contract = null, bool resetStack = false, bool animate = true)
- IObservable PushPage(IViewModel viewModel, string? contract = null, bool resetStack = false, bool animate = true)
- IObservable PushModal(string? contract = null, bool withNavigationPage = true)
- IObservable PushModal(IViewModel modal, string? contract = null, bool withNavigationPage = true)
- IObservable PopPage(bool animate = true)
- IObservable PopModal(bool animate = true)
- IObservable PopToRootPage(bool animate = true)
- IObservable> PageStack / ModalStack
- IObservable TopPage() / TopModal()
Parameter navigation (IParameterViewStackService)
- IObservable PushPage(INavigationParameter parameter, string? contract = null, bool resetStack = false, bool animate = true) where TViewModel : INavigable
- IObservable PushPage(INavigable vm, INavigationParameter parameter, string? contract = null, bool resetStack = false, bool animate = true)
- IObservable PushModal(INavigationParameter parameter, string? contract = null, bool withNavigationPage = true) where TViewModel : INavigable
- IObservable PushModal(INavigable modal, INavigationParameter parameter, string? contract = null, bool withNavigationPage = true)
- IObservable PopPage(INavigationParameter parameter, bool animate = true)
## Parameters and lifecycle (INavigable)
Implement INavigable on your view models to receive lifecycle notifications and parameters.
```csharp
using System;
using System.Reactive;
using Sextant;
public sealed class DetailsViewModel : INavigable
{
public string Id => nameof(DetailsViewModel);
public IObservable WhenNavigatingTo(INavigationParameter parameter)
{
// Called before the page is pushed
return Observable.Return(Unit.Default);
}
public IObservable WhenNavigatedTo(INavigationParameter parameter)
{
// Read parameters
parameter.TryGetValue("itemId", out string id);
return Observable.Return(Unit.Default);
}
public IObservable WhenNavigatedFrom(INavigationParameter parameter)
=> Observable.Return(Unit.Default);
}
```
Passing parameters
```csharp
var param = new NavigationParameter { ["itemId"] = someId };
_appLocator.GetService()
.PushPage(param)
.Subscribe();
```
## View model usage example
```csharp
using System.Reactive;
using ReactiveUI;
using Sextant;
public class HomeViewModel : ViewModelBase
{
public HomeViewModel(IViewStackService nav)
{
OpenDetails = ReactiveCommand.CreateFromObservable(
() => nav.PushPage(),
outputScheduler: RxSchedulers.MainThreadScheduler);
OpenModal = ReactiveCommand.CreateFromObservable(
() => nav.PushModal(),
outputScheduler: RxSchedulers.MainThreadScheduler);
Back = ReactiveCommand.CreateFromObservable(
() => nav.PopPage(),
outputScheduler: RxSchedulers.MainThreadScheduler);
}
public ReactiveCommand OpenDetails { get; }
public ReactiveCommand OpenModal { get; }
public ReactiveCommand Back { get; }
public override string Id => nameof(HomeViewModel);
}
```
## Contracts and modal options
- contract lets you register/resolve alternate views for the same ViewModel.
- withNavigationPage (PushModal) wraps the modal in a navigation page on platforms that support it (e.g., MAUI).
- resetStack replaces the navigation stack with the pushed page.
## Best practices
- Register IViewLocator. If you already use ReactiveUI’s default, register ReactiveUI.ViewLocator.Current as IViewLocator.
- Use AppLocator.CurrentMutable to register views, services, and factories during boot.
- Prefer IParameterViewStackService when passing data or using lifecycle hooks (INavigable).
- Dispose resources in view models implementing IDestructible; Sextant calls Destroy() when a VM is popped.
- Observe on RxApp.MainThreadScheduler when updating UI; Sextant uses IView.MainThreadScheduler internally.
## Samples
This repository contains MAUI and Avalonia samples demonstrating full setups (registration, navigation, parameters, and modal flows). Explore the Samples folder in the repo.
## Contribute
Sextant is developed under an OSI-approved open source license, making it freely usable and distributable, even for commercial use. We appreciate contributions of all kinds: docs, samples, bug reports, and features.
- Answer questions on StackOverflow: https://stackoverflow.com/questions/tagged/sextant
- Share knowledge and help new contributors
- Submit documentation updates where needed
- Make code contributions