Introducción a los Convertidores en Silverlight 2

Introducción

Los Convertidores en el contexto de Silverlight, específicamente en el atado a datos son un mecanismo poderoso para poder cambiar un valor cuando de una fuente de datos se esté atando a un destino, pudiendo ser este destino por ejemplo un control.  El atado de datos en Silverlight funciona a partir de cuatro conceptos:  una fuente, la propiedad de la fuente de la que “leeremos” el dato, el destino y la propiedad del destino al que ataremos el dato.

Un ejemplo claro es cuando una fuente de datos incluye un campo tipo DateTime.  Debido a que el tipo de dato DateTime incluye día, mes, año, horas, minutos, segundos y milisegundos, frecuentemente necesitamos únicamente presentar la fecha y quitar la hora.  O por ejemplo cuando a partir de un campo bool deseamos mostrar las palabras ‘Sí’ o ‘No’ en vez de True y False.

Es aquí cuando los Convertidores son una solución natural, ya que nos permiten transformar (convertir) el dato inicial a otro que represente mejor lo que necesitamos mostrar.

Desarrollo

Iniciemos creando una nueva aplicación Silverlight utilizando la plantilla correspondiente en Visual Studio .NET 2008.  A nuestra solución le llamaremos EjemploConvertidores.

En esta solución tendremos como fuente de datos una lista de álbumes musicales, tal y como lo muestra el siguiente código:

using System;
using System.Collections.Generic;
 
namespace EjemploConvertidores
{
    public class Album
    {
        public string Titulo { get; set; }
 
        public string Banda { get; set; }
 
        public DateTime FechaLanzamiento { get; set; }
    }
 
    public class Albumes : List<Album>
    {
        public Albumes()
        {
            Add(new Album() { Titulo = "Broken", Banda = "Nine Inch Nails", FechaLanzamiento = DateTime.Parse("1992-09-22") });
            Add(new Album() { Titulo = "The Fragile", Banda = "Nine Inch Nails", FechaLanzamiento = DateTime.Parse("1999-09-21") });
            Add(new Album() { Titulo = "Broken", Banda = "Nine Inch Nails", FechaLanzamiento = DateTime.Parse("1994-03-08") });
            Add(new Album() { Titulo = "OK Computer", Banda = "Radiohead", FechaLanzamiento = DateTime.Parse("1997-06-16") });
            Add(new Album() { Titulo = "The Bends", Banda = "Radiohead", FechaLanzamiento = DateTime.Parse("1995-03-13") });
            Add(new Album() { Titulo = "In Rainbows", Banda = "Radiohead", FechaLanzamiento = DateTime.Parse("2007-10-10") });
            Add(new Album() { Titulo = "Black Celebration", Banda = "Depeche Mode", FechaLanzamiento = DateTime.Parse("1986-03-17") });
            Add(new Album() { Titulo = "Ultra", Banda = "Depeche Mode", FechaLanzamiento = DateTime.Parse("1997-04-14") });
            Add(new Album() { Titulo = "Music For The Masses", Banda = "Depeche Mode", FechaLanzamiento = DateTime.Parse("1987-09-28") });
        }
    }
}

Claro está, nuestra fuente de datos puede provenir de un Servicio Web, un Servicio REST, un archivo XML,etc.  Por efectos de simplicidad he modelado directamente en la aplicación las clases Album y Albumes.  Albumes es de tipo List<Album>.  La clase List<T> implementa las interfaces IList y IEnumerable por lo tanto podremos usar Albumes como fuente de datos.

Ahora bien, para este ejemplo declararé el objeto que representa la fuente de datos directamente en markup, esto es, como recurso en el UserControl de Page.xaml.  Hay diferentes maneras de lograr el mismo escenario pero este mecanismo es particularmente más eficiente por el desacoplamiento que logramos.  Además, es necesario recordar que para hacer esto necesitamos importar el espacio de nombres xml en la declaración del control y asignarle un alias.  El alias en este caso se llama ‘app’.  Todo esta idea es mostrada en el siguiente fragmento de código:

<UserControl x:Class="EjemploConvertidores.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:app="clr-namespace:EjemploConvertidores"
    Width="400" Height="300">
    <UserControl.Resources>
        <app:Albumes x:Key="albumes" />
    </UserControl.Resources>
...

El siguiente paso será declarar el control al que deseemos atar la lista de álbumes.  El siguiente fragmento de código muestra un ListBox con un DataTemplate el cual incluye los tres datos de un álbum: título, banda y fecha de lanzamiento; cada uno atándose a un TextBlock.  El concepto de DataTemplate y DataContext será orígen de otro artículo específicamente para el tema de atado de datos.

<UserControl x:Class="EjemploConvertidores.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:app="clr-namespace:EjemploConvertidores"
    Width="400" Height="300">
    <UserControl.Resources>
        <app:Albumes x:Key="albumes" />
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource albumes}">
        <ListBox x:Name="lista" ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Titulo}" FontSize="20" />
                        <TextBlock Text="{Binding Banda}" />
                        <TextBlock Text="{Binding FechaLanzamiento}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</UserControl>

Al ejecutar la aplicación veremos el siguiente resultado:

Como podemos observar, la fecha está mostrando horas, minutos y segundos y muy probablemente no sea la mejor manera de mostrarla.  Es el momento de crear nuestro primer Convertidor.

Creando el Convertidor de Fecha

Agregaremos a nuestra solución un fólder llamado Convertidores y en este fólder una clase llamada ConvertidorFecha.  Usar fólders nos permite tener más organizado nuestro proyecto Silverlight y es una práctica recomendada.

Los Convertidores son clases que implementan la interfaz IValueConverter.  Esta interfaz expone dos métodos que podemos reemplazar:  Convert y ConvertBack.  El primero es el método que se ejecutará cuando estamos atando el dato de la fuete al destino y ConvertBack es el método que se ejecutará cuando el destino cambie el dato y regrese a la fuente original, en escenarios principalmente de tipos de atado TwoWay.

Para nuestro proyecto implementaremos el método Convert de la siguiente manera:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    //El valor de entrada
    DateTime valorEntrada = (DateTime)value;
 
    //El resultado
    string resultado = string.Empty;
 
    //Utilizamos el argumento parameter para poder determinar el formato de la fecha
    resultado = valorEntrada.ToString(parameter.ToString());
    
    return resultado;
}

Es de notar que estamos usando el argumento parameter, el cual representa un parámetro de entrada que podemos establecer cuando realizamos el atado.

Para usar nuestro Convertidor y establecer el parámetro que requiere, modificamos la implementación del Binding en nuestro archivo XAML.  Cada objeto Binding expone diversas propiedades, entre ellas las propiedades Converter y ConverterParameter, siendo el nombre del objeto Convertidor y los parámetros opcionales respectivamente,.

De la  misma manera que dimos de alta la fuente de datos en el diccionario de recursos del UserControl, así expresaremos el Convertidor que acabamos de escribir.  Nótese cómo es requerida la importación del espacio de nombres que representa el fólder creado:

<UserControl x:Class="EjemploConvertidores.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:app="clr-namespace:EjemploConvertidores"
    xmlns:convertidores="clr-namespace:EjemploConvertidores.Convertidores"
    Width="400" Height="300">
    <UserControl.Resources>
        <app:Albumes x:Key="albumes" />
        <convertidores:ConvertidorFecha x:Key="convertidorFecha" />
    </UserControl.Resources>

Finalmente, a nuestro objeto Binding de la FechaLanzamiento le aplicamos el Convertidor, por medio de las propiedades Converter y ConverterParameter.  Por medio de la extensión StaticResource invocamos el Convertidor que dimos de alta en el diccionario de recursos:

<TextBlock Text="{Binding FechaLanzamiento, Converter={StaticResource convertidorFecha}, ConverterParameter='MMMM dd yyyy'}" />

En ConverterParameter estamos usando la cadena ‘MMMM dd yyyy’ aunque podríamos utilizar cualquier formato de fecha soportado.

El resultado final de nuestra aplicación será la siguiente:

En donde podemos observar que efectivamente el dato mostrado es transformado a través del Convertidor que creamos.

Resumen

Los Convertidores son clases que implementan la interfaz IValueConverter y nos sirven para modificar un dato a otro cuando estamos atando una fuente de datos a un destino, por ejemplo un control.  Este tipo de objetos nos brinda una gran flexibilidad ya que con ellos no es necesario modificar nuestra fuente de datos para poder soportar diversas maneras de mostrar la información.

El código fuente de esta aplicación lo pueden descargar de la sección “Contenido” de La Liga Silverlight.