Buenas prácticas aplicando MVVM: Converters (parte 1)

jueves, 12 de junio de 2014

Buenas prácticas MVVM

Seguimos con las buenas prácticas aplicando MVVM, como ya vimos en el primer post de la serie es importante tener muy claro las responsabilidades de cada componente que interviene en MVVM, en esta entrega vamos a ver cómo nos pueden ayudar los converters a esta separación de responsabilidades.

Reflexión

Un converter es una clase que se encarga de convertir, ¿pero convertir qué?, como ya vimos en el segundo post de la serie, la comunicación de la vista con el view model se realiza mediante bindings, pero hay veces que el dato que estamos enlazando no tiene el formato o no es del tipo que necesitamos representar en la vista. Por ejemplo queremos representar los estados que puede tener una factura con colores o queremos ocultar una sección de la vista en función de si existe un dato.

Aquí es donde entran en juego los converters y nos puede ayudar a separar el view model de las responsabilidades de la vista.

Hay desarrolladores que piensan que la labor de un view model es de hacer de enlace entre el modelo y la vista, por lo tanto también es su responsabilidad convertir los valores del modelo a los tipos de datos que necesita la vista.
Por ejemplo en este artículo Josh Smith, famoso por su gran artículo sobre MVVM, y con el que yo me inicié en este patrón, opina que los view models deberían convertir valores.

Yo no estoy de acuerdo aunque lo diga Josh Smith, en el ejemplo del artículo estaríamos haciendo validaciones sobre ancho de un control y para mi esto no es responsabilidad del view model sino de la vista.

Yo soy de la opinión que el view model si que es intermediario entre el modelo y la vista pero no debería acceder a ningún tipo de clase que pertenezca a la vista como pueden ser controles, enumerados que son valores de propiedades de un control etc.. esto va a hacer nuestros view models más reutilizables entre diferentes plataformas como pueden ser WPF, Silverlight, Windows 8 o Windows Phone y no van a estar acoplados a la vista, de forma que futuros cambios en la vista no tienen porque afectar al view model.

Creo que es positivo que el view model no sepa de interpretaciones de como un dato va a ser representado en la vista porque un view model también puede ser compartido entre diferentes vistas dentro del mismo proyecto y el mismo dato se puede representar de diferentes formas según la vista.

Como se usa un Converter

Para usar un converter, lo primero que tenemos que hacer es crearlo.

    
public sealed class ConverterEjemplo : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return valorConvertidoParaLaVista;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return valorConvertidoParaElViewModel;
        }
    }

Después tenemos que definir el namespace donde se encuentra el converter
    
  xmlns:conv="ConvertersEjemplo.Converters"

definir un recurso con un nombre para el converter
    
<Page.Resources>
   <conv:ConverterEjemplo x:Name="RecursoConverter"/>
</Page.Resources>
y ya podemos utilizar el converter con el namespace como prefijo
    
<TextBlock Text="{Binding BindedText,Converter={StaticResource RecursoConverter}}"/>

Vamos a repasar los converters más comunes.

BooleanToVisibilityConverter

Es uno de los converters más comunes y su objetivo es, basándose en una propiedad Boolean convertir a Visibility, de forma que si la propiedad es true, se devuelve Visible y si es false se devuelve Collapsed.

    
public sealed class BooleanToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return value is Visibility && (Visibility)value == Visibility.Visible;
        }
    }

Un ejemplo de uso puede ser tener en el view model una propiedad boolean IsBusy, que se pone a true mientras carga datos y utilizar este converter para mostrar un ProgressRing mientras el view model esta ocupado.

NullObjectToVisibilityConverter

Este es uno de los converters que suelo utilizar también bastante a menudo, devuelve Visible si el objeto enlazado no es nulo y Collapsed si es nulo.

    
public sealed class BooleanToVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return (value is bool && (bool)value) ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            return value is Visibility && (Visibility)value == Visibility.Visible;
        }
    }

ToUpperConverter y ToLowerConverter

Converters para convertir todo un texto a mayusculas o minusculas

public class ToUpperValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var str = value as string;
        return string.IsNullOrEmpty(str) ? string.Empty : str.ToUpper();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}
public class ToLowerValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var str = value as string;
        return string.IsNullOrEmpty(str) ? string.Empty : str.ToLower();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return null;
    }
}

Resumen

En este post he hecho una reflexión sobre los converters, las ventajas que nos pueden aportar y os he dado mi opinión respecto al uso de converters. También hemos visto converters comunes en cualquier proyecto y que perfectamente podrían ser candidatos a incluirse en un framework propio.

En el próximo post seguiremos hablando de converters.

Y vosotros, ¿Que opinión tenéis vosotros sobre el uso de converters?, ¿Que converters soléis utilizar frecuentemente?

Libros Relacionados

MVVM Unleashed
Advanced MVVM


No hay comentarios:

Publicar un comentario