[Xamarin.Forms] Pasar objetos entre paginas utilizando la navegación de Shell


Recientemente me entró la curiosidad por probar la navegación basada en URIS (shell) que esta disponible en Xamarin.Forms desde su versión 4.0. Tras desarrollar una aplicación básica donde fui probando de lo que era capaz shell en términos generales me quedé con un buen sabor de boca, se puede apreciar un rendimiento excepcional, se nota el trabajo que ha habido por parte del equipo de Xamarin, no obstante me encontré con una limitación la cual tiene que ver con el paso de parámetros mediante la navegación de shell, como se puede apreciar en la documentación oficial únicamente se permiten pasar parámetros de tipo string lo cual en algunas situaciones puede no ser suficiente, siendo actualmente imposible pasar objetos más complejos, por eso me decidí ha escribir este articulo donde explicare una solución a este problema.

Para empezar crearemos el modelo del objeto con el que trabajaremos en este ejemplo:
    public class Contact
    {
        public string Name { get; set; }
        public string LastName { get; set; }
        public string Phone { get; set; }
    }
Después instalaremos en nuestro proyecto el nuget Newtonsoft.Json y aquí es donde radica la clave de esta solución, puesto que la navegación shell solo admite parámetros de tipo string con el nuget Newtonsoft serializaremos nuestro objeto a un formato JSON y lo enviaremos como parámetro de navegación, para ello he preparado un método de ejemplo:
        private async Task NavigateToContactBookDetail()
        {
            var jsonContact = JsonConvert.SerializeObject(SendContact);
            ShellNavigationState state = Shell.Current.CurrentState;

            await Shell.Current.GoToAsync($"{state.Location}/contactBookDetail?contact={jsonContact}");
        }
En este ejemplo estoy utilizando el patrón Modelo–vista–modelo de vista (MVVM) por lo que cada pagina tiene su propio View Model (VM), una vez se ha realizado la navegación a la pagina especificada deberemos recoger el JSON que hemos enviado por parámetro y deserializarlo para convertirlo de nuevo en el objeto Contact, a continuación se puede apreciar el View Model de la vista de destino en la cual se define encima de la clase un atributo con dos parámetros el primero de ellos "Contact" tendremos que crear una propiedad en el View Model actual que se llame igual "Contact" y que sea de tipo string ya que sera la encargada recibir el JSON que hemos enviado anteriormente, el segundo parámetro "contact" solo se utiliza en las navegaciones para especificar que se requieren parámetros, como hicimos en la vista anterior para navegar a la actual:
await Shell.Current.GoToAsync($"{state.Location}/contactBookDetail?contact={jsonContact}");
Ahora crearemos un objeto de tipo Contact "ContactReceived" en el cual reconstruiremos el JSON que hemos recibido para ello utilizaremos de nuevo el nuget Newtonsoft y esta vez serializaremos el JSON en el objeto "ContactReceived":
    [QueryProperty("Contact", "contact")]
    public class ContactBookDetailViewModel : BaseViewModel
    {
        private Contact _contactReceived = new Contact();

        public string Contact
        {
            set => ContactReceived = JsonConvert.DeserializeObject<Contact>(Uri.UnescapeDataString(value));
        }

        public Contact ContactReceived
        {
            get => _contactReceived;
            set
            {
                _contactReceived = value;
                RaiseOnPropertyChanged();
            }
        }
    }
Como habéis podido ver de esta forma hemos conseguido suplir una carencia que tiene el sistema de navegación de shell actualmente y podremos enviar cualquier objeto que necesitemos por parámetro basándonos en el concepto de deserializar nuestro objeto en formato JSON en el View Model de origen y en el View Model de destino serializar el JSON resultante en un objeto del mismo tipo. Puedes ver el ejemplo completo en mi GitHub:

Ver ejemplo completo en GitHub 

Comentarios

Entradas populares de este blog

[Xamarin.Forms] Descubriendo el control Expander