Navigation in Xamarin.Forms
Using INavigation from view model
Section titled “Using INavigation from view model”First step is create navigation interface which we will use on view model:
public interface IViewNavigationService{ void Initialize(INavigation navigation, SuperMapper navigationMapper); Task NavigateToAsync(object navigationSource, object parameter = null); Task GoBackAsync();}In Initialize method I use my custom mapper where I keep collection of pages types with associated keys.
public class SuperMapper{ private readonly ConcurrentDictionary<Type, object> _typeToAssociateDictionary = new ConcurrentDictionary<Type, object>();
private readonly ConcurrentDictionary<object, Type> _associateToType = new ConcurrentDictionary<object, Type>();
public void AddMapping(Type type, object associatedSource) { _typeToAssociateDictionary.TryAdd(type, associatedSource); _associateToType.TryAdd(associatedSource, type); }
public Type GetTypeSource(object associatedSource) { Type typeSource; _associateToType.TryGetValue(associatedSource, out typeSource);
return typeSource; }
public object GetAssociatedSource(Type typeSource) { object associatedSource; _typeToAssociateDictionary.TryGetValue(typeSource, out associatedSource);
return associatedSource; }}Enum with pages:
public enum NavigationPageSource{ Page1, Page2}App.cs file:
public class App : Application{ public App() { var startPage = new Page1(); InitializeNavigation(startPage); MainPage = new NavigationPage(startPage); }
#region Sample of navigation initialization private void InitializeNavigation(Page startPage) { var mapper = new SuperMapper(); mapper.AddMapping(typeof(Page1), NavigationPageSource.Page1); mapper.AddMapping(typeof(Page2), NavigationPageSource.Page2);
var navigationService = DependencyService.Get<IViewNavigationService>(); navigationService.Initialize(startPage.Navigation, mapper); } #endregion}In mapper I associated type of some page with enum value.
IViewNavigationService implementation:
[assembly: Dependency(typeof(ViewNavigationService))]namespace SuperForms.Core.ViewNavigation{ public class ViewNavigationService : IViewNavigationService { private INavigation _navigation; private SuperMapper _navigationMapper;
public void Initialize(INavigation navigation, SuperMapper navigationMapper) { _navigation = navigation; _navigationMapper = navigationMapper; }
public async Task NavigateToAsync(object navigationSource, object parameter = null) { CheckIsInitialized();
var type = _navigationMapper.GetTypeSource(navigationSource);
if (type == null) { throw new InvalidOperationException( "Can't find associated type for " + navigationSource.ToString()); }
ConstructorInfo constructor; object[] parameters;
if (parameter == null) { constructor = type.GetTypeInfo() .DeclaredConstructors .FirstOrDefault(c => !c.GetParameters().Any());
parameters = new object[] { }; } else { constructor = type.GetTypeInfo() .DeclaredConstructors .FirstOrDefault(c => { var p = c.GetParameters(); return p.Count() == 1 && p[0].ParameterType == parameter.GetType(); });
parameters = new[] { parameter }; }
if (constructor == null) { throw new InvalidOperationException( "No suitable constructor found for page " + navigationSource.ToString()); }
var page = constructor.Invoke(parameters) as Page;
await _navigation.PushAsync(page); }
public async Task GoBackAsync() { CheckIsInitialized();
await _navigation.PopAsync(); }
private void CheckIsInitialized() { if (_navigation == null || _navigationMapper == null) throw new NullReferenceException("Call Initialize method first."); } }}I get type of page on which user want navigate and create it’s instance using reflection.
And then I could use navigation service on view model:
var navigationService = DependencyService.Get<IViewNavigationService>();await navigationService.NavigateToAsync(NavigationPageSource.Page2, "hello from Page1");Remarks
Section titled “Remarks”The navigation on Xamarin.Forms is based on two principal navigation patterns: hierarchical and modal.
The hierarchical pattern allows the user to move down in a stack of pages and return pressing the “back”/“up” button.
The modal pattern is a interruption page that require a specific action from user, but normally can be canceled pressing the cancel button. Some examples are notifications, alerts, dialog boxes and register/edition pages.