Prism para Xamarin [Segunda parte]

//Prism para Xamarin [Segunda parte] : Event Aggregator y EventToCommandBehavior

Prism para Xamarin [Segunda parte] : Event Aggregator y EventToCommandBehavior

En esta segunda entrega de Prism hablaremos de dos recursos muy potentes: Event Aggregator y EventToCommandBehavior para que podamos incorporarlos en nuestras aplicaciones.

Para seguir con este post os recomendamos leer la primera parte ya que vimos conocimientos básicos que se darán por sabidos para continuar con esta segunda.

Event Aggregator

Prism nos proporciona un mecanismo de eventos que permite la comunicación entre distintos componentes acoplados en nuestra aplicación. Este mecanismo se basa en el patrón de mensajería Publish/Subscribe. En el cual los publicadores (Publisher) notifican a sus suscriptores (Subscribers) que previamente se han suscrito a recibir dichos mensajes.

Esto ocurre gracias a la clase EventAggregator que funciona como un servicio que se encarga de agregar los eventos para que los publicadores y subscriptores puedan comunicarse sin necesidad de conocerse entre ellos. Esta clase hereda de EventBase permitiendo a suscriptores y publicadores localizar el evento determinado.

Este “agregador” de eventos también permite múltiples suscriptores y publicadores, tan como se muestra en el gráfico que nos ofrece la documentación de Prism:

A continuación, crearemos el siguiente ejemplo práctico muy sencillo para aprender a usarlo:

  • Desde una pantalla “Editar” cambiaremos por medio de un Entry nuestro nombre de usuario (publish) y automáticamente visualizaremos este cambio en un elemento Label que tenemos en la pantalla MasterDetailPage (subscribe).

Crear un evento

Primero crearemos el evento usando la clase genérica PubSubEvent y el tipo de mensaje que se pasará a los suscriptores. En nuestro caso al ser un Entry de tipo texto será string:

______

 public class UserProfileUpdateEvent : PubSubEvent { }

Esta funciona como una clase base para todos los eventos realizando el trabajo de conectar publicadores y suscriptores gracias a la implementación de la clase EventBase. La cual contiene la lista de suscriptores y maneja el envío de eventos a estos suscriptores.

Publicar un evento

Ahora que tenemos el evento creado vamos a aprender a lanzarlo desde nuestro publicador.

En nuestro caso lo lanzaremos desde el comando que se llamará cuando terminemos de editar el Entry con el nuevo nombre.

Primero tenemos que localizar y construir el evento anterior usando la clase EventAggregator por medio del método GetEvent<>. Esta clase nos la ofrece Prism como un servicio contenedor, de tal manera que la tenemos disponible para usarla con inyección de dependencias, agregando el parámetro de tipo IEventAggretor en nuestro constructor.

Con el evento a nuestra disposición lanzaremos su método Publish de la clase PubSubEvets justo en el comando que se lanza cuando el usuario termina de escribir, mandando el nuevo nombre como parámetro como observamos en el siguiente código:

______
public class EditUserViewModel : ViewModelBase
    {
readonly UserProfileUpdateEvent _event;

        public EditProfileViewModel(INavigationService navigationService, IEventAggregator ea)
            : base(navigationService)
        {
            Title = "Edit Profile";

            _event = ea.GetEvent();  
        }
DelegateCommand _saveProfileCommand;
        public ICommand SaveProfileCommand
{
get
            {
                return _saveProfileCommand ??
                    (_saveProfileCommand = new DelegateCommand(OnSaveProfileButton));
            }
        }        
private void OnSaveProfileButton()
        {
            // Send Event
            _event.Publish(NickName);
        }

        private string _nickName;
        public string NickName
        {
            get { return _nickName; }
            set { SetProperty(ref _nickName, value); }
        }
}

Suscribirse a eventos

Para escuchar este evento en nuestra MasterDetailPage y poder cambiar nuestro Label con los nuevos cambios, tenemos que seguir el mismo mecanismo del paso anterior: recoger desde nuestro constructor el servicio EventAggregator para localizar y construir el evento para después suscribirse por medio del método Subcribe que también ofrece PubSubEvents.

De esta manera estaremos suscritos siempre y cuando se llame el evento desde el otro lado. Recogeremos el valor del texto por medio de un delegado que asignaremos a la vista por medio un Binding.

Existen más formas de suscribirse al evento utilizando las distintas sobrecargas del método Subcribe y así usar el que mejor se adapte nuestras necesidades, en nuestro caso con el más sencillo sirve:

______
public class CustomMasterDetailPageViewModel : ViewModelBase
    {
        private string _nickName;
        public string NickName
        {
            get { return _nickName; }
            set { SetProperty(ref _nickName, value); }
        }

        readonly UserProfileUpdateEvent _event;
        readonly SubscriptionToken _token;

        public CustomMasterDetailPageViewModel(INavigationService navigationService, IEventAggregator ea)
            : base(navigationService)
        {
            _event = ea.GetEvent();
            _token = _event.Subscribe(e => NickName = e , ThreadOption.PublisherThread);
        }

        public override void Destroy()
        {
            base.Destroy();
            _event.Unsubscribe(_token);
        }
    }

Darse de baja de un evento

Es importante de suscribirse a los eventos cuando no los necesitamos o si por alguna razón ya no queremos seguir escuchando.

Para ello podemos hacerlo de dos formas utilizando el controlador del subscriptor o como podemos observar en el ejemplo, mediante el token que devuelve el método Subscribe y llamar al método Unsubscribe. De esta manera se eliminará de la lista de suscriptores.

EventToCommandBehavior

La clase EventToCommandBehavior es un comportamiento personalizado de xamarin.Forms que ejecuta un comando en respuesta a la activación de cualquier evento.

Por defecto los eventos en Xamarin Forms se crean en code behing y desde ahí se suele llamar al comando del ViewModel o directamente se hace la implementación en code behing ensuciando de esta manera el paradigma MVVM.

Para evitarlo es una buena práctica aprender a usar esta clase para vincular eventos y evitar escribir código subyacente.

Uso

Como ejemplo práctico “bindaremos” a un comando el evento Tapped de un elemento ListView de nuestra vista y después le pasaremos como parámetro el objeto del listado seleccionado.

Para ello creamos la clase EventToCommandBehavior de Prism adjuntándola a la colección Behaviors.

Las propiedades básicas que tenemos que configurar son EventName, nombre del evento (en nuestro caso ItemTapped) y Command, donde bindeamos nuestro comando del ViewModel. Tal y como podemos observar en este fragmento de XAML:

            
    <ListView.Behaviors>
            <prism:EventToCommandBehavior EventName="ItemTapped"
                                          Command="{Binding ItemTappedCommand}"/>
        </ListView.Behaviors>    

Pasar argumentos

Adicionalmente podemos pasarle argumentos a los comandos por medio de CommandParameter, EventArgsParameterPath o EventArgsConverter.

En nuestro ejemplo le pasaremos el objeto seleccionado de dos formas, primero os enseñare como pasar el objeto creando un converter y asociándolo a la propiedad EventArgsConverter y después usando directamente la propiedad EventArgsParameterPath.

Para el primer tenemos que crear y hacer uso del converter “ItemTappedEventArgsConverter” que implementa la interfaz IValueConverter. Este cambiará el formato de los datos entre origen y destino devolviendo el elemento visual del argumento del evento ItemTapped (ItemTappedEventArgs):

______
    public class ItemTappedEventArgsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var itemTappedEventArgs = value as ItemTappedEventArgs;
            if (itemTappedEventArgs == null)
            {
                throw new ArgumentException("Expected value to be of type ItemTappedEventArgs", nameof(value));
            }
            return itemTappedEventArgs.Item;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Después referenciamos el converter en nuestro EventToCommandBehavor y este devolverá el elemento visual que está usando el evento ItemTapped. De tal manera que al pulsar nuestro comando recibirá el objeto seleccionado como hemos comentando antes gracias al converter:

    
        <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class=" Prism.Practice.II.Views.MainPage"
             xmlns:prism="http://prismlibrary.com"
             xmlns:cv="clr-namespace:Prism.Practice.II.Converters">
    <ContentPage.Resources>
        <ResourceDictionary>
            <cv:ItemTappedEventArgsConverter x:Key="itemTappedEventArgsConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <ListView ItemsSource="{Binding Listado}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Label Text="{Binding NickName}" />
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        <ListView.Behaviors>
            <prism:EventToCommandBehavior EventName="ItemTapped"
                                          Command="{Binding ItemTappedCommand}"
                                          EventArgsConverter="{StaticResource itemTappedEventArgsConverter}" />
        </ListView.Behaviors>
    </ListView>
</ContentPage>

Otra forma de pasar el elemento seleccionado directamente evitando el uso del converter anterior es usando la propiedad EventArgsParameterPath. De esta manera indicaremos que queremos el elemento visual directamente “Item”:

                
  <ListView.Behaviors>
                <prism:EventToCommandBehavior Command="{Binding ItemTappedCommand}"
                                              EventArgsParameterPath="Item"                   
                                              EventName="ItemTapped" />
            </ListView.Behaviors>

¡Hasta aquí la segunda entrada entrega de Prism, a la espera de nuevos posts más útiles!

Documentación

Prism Library

Prism Library Xamarin Forms

Escrito por: Rebeca Garnacho, parte del equipo de Movilidad en Bravent.

2020-02-27T11:13:21+00:0027 febrero, 2020|Categories: Movilidad|0 Comments
Translate »