Xamarin.Forms
Navegación en Xamarin. Formas
Buscar..
Observaciones
La navegación en Xamarin.Forms se basa en dos patrones de navegación principales: jerárquico y modal.
El patrón jerárquico permite al usuario moverse hacia abajo en una pila de páginas y regresar presionando el botón "atrás" / "arriba".
El patrón modal es una página de interrupción que requiere una acción específica del usuario, pero normalmente se puede cancelar presionando el botón de cancelar. Algunos ejemplos son notificaciones, alertas, cuadros de diálogo y páginas de registro / edición.
Usando INavigation desde el modelo de vista
El primer paso es crear una interfaz de navegación que usaremos en el modelo de vista:
public interface IViewNavigationService
{
void Initialize(INavigation navigation, SuperMapper navigationMapper);
Task NavigateToAsync(object navigationSource, object parameter = null);
Task GoBackAsync();
}
En el método de Initialize
, uso mi asignador personalizado donde mantengo la colección de tipos de páginas con claves asociadas.
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;
}
}
Enumerar con páginas:
public enum NavigationPageSource
{
Page1,
Page2
}
Archivo App.cs
:
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
}
En el mapeador asocié el tipo de alguna página con el valor enum.
Implementación de IViewNavigationService
:
[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.");
}
}
}
Obtengo el tipo de página en la que el usuario desea navegar y crear su instancia utilizando la reflexión.
Y luego podría usar el servicio de navegación en el modelo de vista:
var navigationService = DependencyService.Get<IViewNavigationService>();
await navigationService.NavigateToAsync(NavigationPageSource.Page2, "hello from Page1");