Data Binding en WPF. 3º Parte. Converters.

En muchas ocasiones lo que tomamos de la base de datos no esta con el formato adecuado para mostrar en la interfaz de usuario. Por ejemplo, obtenemos un decimal de la base de datos con un precio pero deseamos mostrar dicho valor adecuadamente ( 10 € por ejemplo ).

Por suerte, WPF incorpora funcionalidad bastante potente destinada a realizar conversiones de datos de cara a prepararla para la interfaz de usuario.

IValueConverter

El eje central de las conversiones las lograremos implementando la interfaz IValueConverter.
Esta interfaz nos exigira implementar dos métodos:

Convert. Convierte un tipo de entrada en otro de salida.
ConvertBack. Nos realiza la operación inversa.

Veamos a continuación, como sería una implementación vacía de la interfaz:

public class miConversor : IValueConverter
{
     public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     {

     }

     public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     {

     }
}

El método convert convierte el valor del objeto value y se devuelve como un objeto de salida en el mismo método (fíjate que el método converter devuelve un tipo object).

El metodo convertback realiza la operación inversa siempre y cuando se pueda realizar. Comentamos siempre  cuando, porque en ocasiones no se podrá realizar la operación inversa. En dichos casos, y sabiendo que nunca lo llamaremos lo mejor es no implementar de manera explícita el método convertback. Evitar hacer esto a toda costa si el binding que utiliza el converter es en modo two-way.

Para definir el converter de manera adecuada también se deberá añadir a la clase el atributo ValueConversion.
Este atributo definira el tipo del objeto de entrada a convertir, y el tipo del resultado una vez convertido.
Para entender esto mejor, veamos un ejemplo muy sencillo. Vamos a convertir un entero a string:

[ValueConversion(typeof(int), typeof(string))]

Ya hemos hablado mucho de converters sin ver ningún ejemplo completo. Imaginate que en una base de datos tienes un entero que simboliza en nivel de calidad de una película:

1      Horrible
2      Mala
3      Regular
4      Buena
5      Obra Maestra

Tras obtener un valor de la base de datos (por ejemplo, el valor 3), lo ideal no es hacer el binding sin mas a la interfaz porque de cara al usuario final, un 3 no le puede decir nada.

¿que hacemos?

Un converter. Veamos como sería:


namespace EjemploConverter;

[ValueConversion(typeof(int), typeof(string))]
public class intToStringConverter : IValueConverter
{
 public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
 {
      int a = int.Parse(value,toString());

      switch(a)
      {
            case 1:               return "Horrible";
            case 2:               return "Mala";
            case 3:               return "Regular";
            case 4:               return "Buena";
            case 5:               return "Obra Maestra";
            default:              return "Sin clasificación";
      }
 }

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
 {
      string a = value.toString();

      switch(a)
      {
            case "Horrible":               return 1;
            case "Mala":                   return 2;
            case "Regular":                return 3;
            case "Buena":                  return 4;
            default:                       return 5;
      }
 }
}

¿Bien hasta aquí?. La siguiente pregunta lógica es, ¿cómo uso el converter en el XAML?

Lo primero que debemos hacer es añadir una referencia al namespace donde está definido el converter.

<Windowx:Class="EjemploConverter.Window1"
...   xmlns:converter="clr-namespace:EjemploConverter"    ...>
 ...
</Window>

A continuación, lo que debemos hacer es crear una instancia del converter, normalmente se realiza en la colección de recursos:

<Window.Resources>
     <converter:intToStringConverterx:Key="converter"/>
</Window.Resources>

Después de crear la instancia del mismo, debemos utilizarlo en el binding establenciendolo en la propiedad Converter.

<Grid>
     <Label Content="{Binding filmCode,  Converter={StaticResource converter}}"/>
</Grid>

Usar Converters para lograr distintos formatos

Uno de los grandes usos de los converters es el de dar distintos formatos a string de cara a la interfaz de usuario.
Ya hemos visto anteriormente un ejemplo de esto. Casos como:

– Fechas
– Monedas
– Documentos varios (número de la seguridad social, número N.I.F, etc.)

Dando formato a monedas

Es el ejemplo más sencillo que podemos analizar de como utilizar converters para dar formato a string. Normalmente, en la base de datos almacenados los valores monetarios sin formato. Cuando obtenemos el valor de la base de datos (por ejemplo, un decimal de valor 7,95) queremos que en la capa visual se muestre el valor con formato, es decir, en el caso del ejemplo anterior, 7,95 €.
Para conseguir el resultado deseado podemos utilizar el método ToString de los valores numéricos. Sólo debemos insertar el carácter ‘C’ como mostramos a continuación:

string resultadoMoneda = miDouble.ToString("C");

Con esta sencilla operación podemos obtener un valor numérico por ejemplo un Decimal dentro del método Convert de un converter y transformarlo en un string formateado. Es decir, crearíamos un converter que recibe un decimal y devuelve un string.
Veamos como sería:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
     decimal valor = decimal.Pare(value.ToString());

     return a.ToString("C");
}

Nada más por hoy. Espero que la entrada os resulte útil. Hasta la próxima.

Anuncios

Data Binding en WPF. 2º Parte. Introducción.

En el artículo anterior aprendimos que era el databinding junto al caso más sencillo que podemos realizar, el enlace entre las propiedades de dos controles.
En este artículo vamos a seguir profundizando en las características y opciones básicas que nos brinda.

¿Cómo crear binding desde código?

Ya hemos visto como crear un binding entre dos controles sencillo de manera declarativa en el XAML.  Así que puedes estar pensando que para que demonios ibas a querer crear un binding desde código.
Sencillo, si quieres crear o quitar de manera dinámica uno, es la forma de hacerlo.
Lo básico para ello es tener en cuanta que debemos utilizar el método SetBinding en el elemento de la interfaz WPF necesario. Además, debemos establecer la propiedad de dependencia a la que se le asignará el valor en el binding.

Veamos como sería por código el ejemplo del artículo anterior:

Binding miBinding = new Binding();
miBinding.ElementName = "textBox1";
miBinding.Path = new System.Windows.PropertyPath("Text");
textBox2.SetBinding(TextBox.TextProperty, miBinding);

¿Cómo eliminar un binding desde código?

BindingOperations.ClearBinding(textBox2, TextBox.TextProperty);

Podéis descargar el ejemplo explicado anteriormente del enlace de aquí.

Data Binding en WPF. 1º Parte. Introducción.

Data binding es un mecanismo mediante el cual podemos enlazar los elementos de la interfaz de usuario con los objetos que contienen la información a mostrar. El caso más típico de data binding es el enlazar un control de la interfaz de usuario con un valor o registro de una base de datos.
Las posibilidades que nos brinda el data binding en WPF para conseguir interfaces dinámicas y mucho más ricas en contenido son mucho mayores que las posibilidades que teníamos en Windows Forms. Ahora podremos modificar el contenido de un control al modificar otro son tener que escribir código extra en eventos, todo esto y mucho más lo hará el binding por nosotros.

WPF nos permite de manera sencilla realizar binding a una propiedad de un control utilizando propiedades de otros controles, objetos, colecciones, etc.

Cuando realizamos data binding, creamos una dependencia entre el valor de una propiedad llamada target con el valor de otra propiedad llamada source. Donde normalmente, la propiedad target recibirá el valor de la propiedad source. Como veremos en artículos posteriores, podremos modificar el comportamiento del binding. Es decir, en ocasiones, cualquier cambio en el valor de la propiedad source será aplicado a la propiedad target. Sin embargo, podremos hacer que cualquier cambio en la propiedad source sea aplicado a la propiedad target y viceversa.

Todo lo anterior visto lo conseguimos mediante la clase Binding (System.Windows.Data).

La clase Binding es la que nos permite realizar el data binding. En ella es donde se establece el tipo de relación entre las propiedades target y source anteriormente vistas. Se utiliza desde XAML con la notación {Binding …} o mediante la notación explícita <Binding …>…</Binding>.

El enlace de una fuente de datos (source) con un destino de datos (target) nos ahorra tener que estar escribiendo código de la forma:

MiElementoInterfaz.Valor = MiAplicacion.Dato

Además, evita tener que escribir código para mantener sincronizados los datos en ambos extremos del enlace.

Veamos cuales son las propiedades principales de esta clase:

ElementName Obtiene o establece el nombre del elemento que se va a utilizar como objeto de origen de enlace.

Mode Obtiene o establece un valor que indica la dirección del flujo de datos en el enlace. PathObtiene o establece la ruta de acceso a la propiedad del origen de enlace.

SourceObtiene o establece el objeto que se va a utilizar como origen de enlace.

NotifyOnSourceUpdatedObtiene o establece un valor que indica si se va a generar el evento SourceUpdated cuando se transfiere un valor del destino de enlace al origen de enlace.

NotifyOnTargetUpdatedObtiene o establece un valor que indica si se va a generar el evento TargetUpdated cuando se transfiere un valor del origen de enlace al destino de enlace.

XPathObtiene o establece una consulta XPath que devuelve el valor en el origen de enlace XML que se va a usar.

 

Binding a un control WPF

El caso más simple y por ello más fácil de entender de un data binding es enlazar la propiedad de un control WPF a la propiedad de otro control.
Pongamos un ejemplo. Tenemos una ventana con un grid que contiene dos textbox. Queremos conseguir que el contenido del segundo textbox (propiedad Text) haga binding a la propiedad Text del primer TextBox. De este modo, cada ve que escribamos algo en el textbox se verá reflejado en el segundo.

Sería algo así:

<TextBox Text="{Binding ElementName=textBox1, Path=Text}"/>

El elemento donde está el origen de datos lo especificamos mediante la propiedad ElementName, mientras que la propiedad de ese elemento donde está el valor deseado lo especificamos mediante la propiedad Path.

Lo escrito anteriormente es facilmente entendible pero en ocasiones no será así. El binding puede llegar a ser mas complejo y para facilitar la lectura y comprensión del mismo en el XAML podemos escribir exactamente lo mismo de la siguiente manera:

<TextBox>
     <TextBox.Text>
          <Binding ElementName="TextBox1" Path="Text" />
     </TextBox.Text>
</Textbox>

Esta sintaxis mas formal es mas larga y puede que de entrada os resulte mas incomoda pero os aseguro que en muchas ocasiones os facilita la compresión del binding.

<Grid>
     <Label>Fuente de datos:</Label>
     <TextBox Name="textBox1" Margin="2" Grid.Column="1" Text="Valor Inicial"/>
     <Label Grid.Row="1">Destino de datos:</Label>
     <TextBox Margin="2" Grid.Row="1" Grid.Column="1" Text="{Binding ElementName=textBox1, Path=Text}"/>
</Grid>

Al elemento fuente hay que darle un nombre para poderse referir a el en el elemento destino.
Si se modifica el texto dentro del primer TextBox, se puede observar cómo cambia simultáneamente el texto del segundo.

Podéis descargar el ejemplo explicado anteriormente del enlace de aquí.