Artículo escrito por: Néstor Fernández.

Twitter: @xamlparaadeptos

COLECCIONES QUE REPORTAN CAMBIOS

Los bindings son muy útiles cuando necesitamos mantener algo de sincronía entre los valores de dos propiedades. Sin embargo, no es fácil implementar un binding en algunas ocasiones:

  • Cuando las dos propiedades son de tipos diferentes.
  • Cuando el origen es un objeto y no una propiedad.
  • Cuando, aunque del mismo tipo, el valor en el origen no es exactamente el que queremos llevar hasta el destino.

Para cualquiera de estas necesidades contamos con los converters. Un converter es una clase que se conecta a un binding y puede alterar el valor que pasa desde la propiedad de origen al destino y/o viceversa. Estas clases implementan la interfaz IValueConverter que solo requiere definir dos métodos:

  • Convert: Que se invoca cuando el valor de la propiedad de origen viaja hasta la propiedad de destino.
  • ConvertBack: Que se invoca cuando el valor de la propiedad de destino viaja hasta la propiedad de origen.
DEFINICIÓN DE UN CONVERTER

En su representación más simple un converter se define así:

1: publicclass MiConverter : IValueConverter 2: { 3: publicobject Convert(objectvalue, Type targetType, object parameter, System.Globalization.CultureInfo culture) { } 4: publicobject ConvertBack(objectvalue, Type targetType, object parameter, System.Globalization.CultureInfo culture) { } 5: }

Los converters, al no ser controles, deben incluirse preferiblemente en un diccionario de recursos:

1: <Page.Resources> 2: <local:MiConverterx:Key="LlaveConverter"/> 3: Page.Resources>

Y en un binding se asignan a la propiedad Converter de dicho binding:

1: <TextBoxText="{Binding Path=Fecha, Converter={StaticResource LlaveConverter}}"/>
EJEMPLOS

Para los ejemplos utilizaremos el siguiente escenario: Una clase como nuestra fuente de datos:

1: publicclass ClasePersona 2: { 3: publicstring Nombre { get; set; } 4: public DateTime FechaNacimiento { get; set; } 5: publicint Saldo { get; set; } 6: }

A su vez la instanciaremos directamente en XAML y la definiremos como el DataContext de un Grid dentro de una página. El converter que utilizaremos también lo definiremos dentro del diccionario de recursos de una página:

1: <Page.Resources> 2: <local:ClasePersonax:Key="Persona"Nombre="Aura Fernandez"FechaNacimiento="9/13/1969"Saldo="12500"/> 3: <local:MiConverterx:Key="LlaveConverter"/> 4: Page.Resources> 5:  6: <GridDataContext="{StaticResource Persona}"> 7: ... 8: Grid>
EJEMPLO 1

Este converter puede tomar un dato del tipo DateTime y convertirlo en el nombre del mes correspondiente a esa fecha. Nótese que para este ejemplo el binding no está definido como TwoWay, de modo que no es necesario definir el método ConvertBack.

1: publicclass MiConverter : IValueConverter publicobject Convert(objectvalue, Type targetType, object parameter, System.Globalization.CultureInfo culture) 2: { 3: int NumeroMes = ((DateTime)value).Month; 4: return System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.MonthNames[NumeroMes]; 5: } 6:  7: publicobject ConvertBack(objectvalue, Type targetType, object parameter, System.Globalization.CultureInfo culture) 8: { returnnull; } 9: }

Y así se utilizan dentro de, por ejemplo, un TextBlock:

1: <GridDataContext="{StaticResource Persona}"> 2: <TextBlockText="{Binding Path=FechaNacimiento, Converter={StaticResource LlaveConverter}}"/> 3: Grid>

En este caso debemos observar en el TextBlock la cadena "septiembre".

EJEMPLO 2

Aquí tenemos un converter que toma una cadena y devuelve una brocha. Lo utilizaremos para crear una ayuda visual que se torne roja cuando la cadena esté vacía o contenga menos de 5 caracteres, o de lo contrario que cambie a verde. De esta forma podemos, por ejemplo, informar visualmente al usuario cuando una regla o condición no se esté cumpliendo.

1: public class MiConverter : IValueConverter 2: { 3: static SolidColorBrush ColorRojo = new SolidColorBrush(Colors.Red); 4: static SolidColorBrush ColorVerde = new SolidColorBrush(Colors.Green); 5:  6: public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 7: { 8: var Texto = System.Convert.ToString(value); 9: if (string.IsNullOrWhiteSpace(Texto) || Texto.Length < 5) 10: return ColorRojo; 11: else 12: return ColorVerde; 13: } 14:  15: public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 16: { 17: return null; 18: } 19: }

Lo podemos utilizar, por ejemplo, como color de fondo de cualquier otro elemento:

1: <EllipseWidth="100" 2: Height="100" 3: Fill="{Binding Path=Nombre, Converter={StaticResource MiConverter}}"/>
EJEMPLO 3

Este converter nos facilitará calcular un impuesto cualquiera para un un valor numérico. Obsérvese el uso del parámetro "parameter" que podemos asignar convenientemente desde el binding. En otras palabras este binding recibe dos valores: el valor enlazado por el binding y uno adicional (parameter) que utilizaremos para indicar el porcentaje del impuesto.

1: publicclass ImpuestoConverter : IValueConverter 2: { 3: publicobject Convert(objectvalue, Type targetType, object parameter, System.Globalization.CultureInfo culture) 4: { 5: int Valor = System.Convert.ToInt32(value); 6: double Impuesto = System.Convert.ToDouble(parameter); 7: return (Valor * Impuesto / 100).ToString("#,##0.00"); 8: } 9:  10: publicobject ConvertBack(objectvalue, Type targetType, object parameter, System.Globalization.CultureInfo culture) 11: { 12: returnnull; 13: } 14: }

Y lo utilizamos así:

1: <TextBlockText="{Binding Path=Saldo, Converter={StaticResource ImpuestoConverter}, C}, ConverterParameter=16.5}"/>
PARA SABER MÁS… Converting data for display in controls