Sextant
A ReactiveUI view model based navigation library
Sextant was born from a fork of Xamvvm which is nice and simple MVVM Framework with a good navigation system. The problem is, I just wanted a simple navigation system to use with ReactiveUI without all the things that come along an MVVM framework. Plus, I wanted to make it more "Reactive Friendly".
Then a wild Rodney Littles appears, and with him an implementation of this AMAZING POST by Kent
Sextant is in a very initial stage and in constant change, so please be pantience with use... because we will break things.
This library is nothing more than me "standing on the shoulders of giants": Kent for been the original and true creator of this, I pretty much just copied and pasted it :) Geoffrey Huntley maintainer on ReactiveUI.
NuGet Installation
Install the nuget package on your Forms project and ViewModels project.
GitHub
Pre release packages are available at https://nuget.pkg.github.com/reactiveui/index.json
NuGet
Platform | Sextant Package | NuGet |
---|---|---|
UWP | Sextant | |
Xamarin.Forms | Sextant.XamForms | |
Xamarin.Forms | Sextant.Plugins.Popup | |
Xamarin.iOS | Sextant | |
Avalonia | Sextant.Avalonia |
Target Platform Versions
minimum version for your target platform (i.e. Android, iOS, Tizen).
Verify you have theRegister Components
Views
Version 2.0 added new extensions methods for the IMutableDepedencyResolver
that allow you to register an IViewFor
to a View Model.
Locator
.CurrentMutable
.RegisterNavigationView(() => new NavigationView(RxApp.MainThreadScheduler, RxApp.TaskpoolScheduler, ViewLocator.Current))
.RegisterParameterViewStackService()
.RegisterViewForNavigation(() => new PassPage(), () => new PassViewModel())
.RegisterViewForNavigation(() => new ReceivedPage(), () => new ReceivedViewModel());
Set the initial page:
Locator
.Current
.GetService<IParameterViewStackService>()
.PushPage<PassViewModel>()
.Subscribe();
MainPage = Locator.Current.GetNavigationView("NavigationView");
Use the Navigation Service
After that all you have to do is call one of the methods inside your ViewModels:
/// <summary>
/// Pops the <see cref="IPageViewModel"/> off the stack.
/// </summary>
/// <param name="animate">if set to <c>true</c> [animate].</param>
/// <returns></returns>
IObservable<Unit> PopModal(bool animate = true);
/// <summary>
/// Pops the <see cref="IPageViewModel"/> off the stack.
/// </summary>
/// <param name="animate">if set to <c>true</c> [animate].</param>
/// <returns></returns>
IObservable<Unit> PopPage(bool animate = true);
/// <summary>
/// Pushes the <see cref="IPageViewModel"/> onto the stack.
/// </summary>
/// <param name="modal">The modal.</param>
/// <param name="contract">The contract.</param>
/// <returns></returns>
IObservable<Unit> PushModal(IPageViewModel modal, string contract = null);
/// <summary>
/// Pushes the <see cref="IPageViewModel"/> onto the stack.
/// </summary>
/// <param name="page">The page.</param>
/// <param name="contract">The contract.</param>
/// <param name="resetStack">if set to <c>true</c> [reset stack].</param>
/// <param name="animate">if set to <c>true</c> [animate].</param>
/// <returns></returns>
IObservable<Unit> PushPage(IPageViewModel page, string contract = null, bool resetStack = false, bool animate = true);
Example
public class ViewModel
{
private readonly IViewStackServicen _viewStackService; // or IParameterViewStackServicen
public ViewModel(IViewStackServicen viewStackService)
{
_viewStackService = viewStackService;
OpenModal = ReactiveCommand
// FirstModalViewModel must implement IViewModel or INavigable
.CreateFromObservable(() => viewStackService.PushModal<FirstModalViewModel>(),
outputScheduler: RxApp.MainThreadScheduler);
}
public ReactiveCommand<Unit, Unit> OpenModal { get; }
}
Pass Parameters
Version 2.0 added support for passing parameters when navigating.
Example
public class ViewModel
{
private readonly IParameterViewStackServicen _viewStackService;
public ViewModel(IParameterViewStackServicen viewStackService)
{
_viewStackService = viewStackService;
Navigate = ReactiveCommand
// NavigableViewModel must implement INavigable
.CreateFromObservable(() => viewStackService.PushModal<NavigableViewModel>(new NavigationParameter { { "parameter", parameter } }),
outputScheduler: RxApp.MainThreadScheduler);
}
public ReactiveCommand<Unit, Unit> Navigate { get; }
}
The INavigable
interface exposes view model lifecycle methods that can be subscribed to. These methods unbox your parameter object. Implementing the interface allows you to assign values to the View Model during Navigation.
public class NavigableViewModel : INavigable
{
public string? _parameter;
public IObservable<Unit> WhenNavigatedFrom(INavigationParameter parameter)
{
return Observable.Return(Unit.Default)
}
public IObservable<Unit> WhenNavigatedTo(INavigationParameter parameter)
{
parameter.TryGetValue("parameter", out _parameter);
return Observable.Return(Unit.Default);
}
public IObservable<Unit> WhenNavigatingTo(INavigationParameter parameter)
{
return Observable.Return(Unit.Default);
}
}
Samples
Contribute
Sextant is developed under an OSI-approved open source license, making it freely usable and distributable, even for commercial use. We β€ the people who are involved in this project, and weβd love to have you on board, especially if you are just getting started or have never contributed to open-source before.
So here's to you, lovely person who wants to join us β this is how you can support us:
- Responding to questions on StackOverflow
- Passing on knowledge and teaching the next generation of developers
- Submitting documentation updates where you see fit or lacking.
- Making contributions to the code base.