jueves, 18 de junio de 2009

Data Binding IV

Multi Binding - IMultiValueConverter :
MultiBinding :
La clase MultiBinding describe una colección de objetos Binding asociados a una sola propiedad de destino de enlace.
MultiBinding permite enlazar una propiedad del destino de enlace a una lista de propiedades de origen y, a continuación, aplicar la lógica para generar un valor con las entradas indicadas.

IMultiValueConverter:
Proporciona una forma de aplicar la lógica personalizada a una clase MultiBinding.
Para asociar un convertidor a una clase MultiBinding, se debe crear una clase que implemente la interfaz IMultiValueConverter y, a continuación, los métodos Convert y ConvertBack.

En otras palabras, podemos tener múltiples propiedades de origen de enlace para una propiedad de destino de enlace.Sin embargo, la propiedad de destino de enlace sólo recibe una propiedad que no necesariamente es una de las de origen de enlace, sino el resultado de la lógica de conversion implementada en una clase que implementa la interfaz IMultiValueConverter.

Por ejemplo, la propiedad RenderTransform de un objeto Image recibe un objeto Transform que puede ser un ScaleTransform,RotateTransform,etc...
Para instanciar la clase RotateTransform se requieren -no necesariamente- tres valores de tipo double(angulo,coordenada X i Y del punto central de la rotación), los cuales se envían como parámetro a su constructor.

Ahora bien, Qué hago si tuviera una objeto Image al cual quisiera rotar de manera que el angulo de rotación y las coordenadas X i Y cambien en función de otros procesos?.

Pues, la respuesta es: MultiBinding + IMultiValueConverter.

Para hecerlo mas comprensivo he hecho un pequeño ejemplo.Una pequeña aplicación que rota un objeto Image en base a los valores de tipo double de la propiedad Value de tres Slider´s.
La propiedad RenderTransform(destino de enlace) del objeto Image, enlaza a tres propiedades de origen de enlace: la propiedad Value de cada Slider(líneas 33,34 y 35).

Muestro el código XAML :


   1:  <Window x:Class="TestWPF_Data_Binding_II.DataBinding_MultiBinding"

   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   4:      xmlns:local="clr-namespace:TestWPF_Data_Binding_II"

   5:      Title="DataBinding_MultiBinding" Height="740" Width="768">

   6:      <Window.Resources>

   7:          <local:DoubleRotateTransform x:Key="Convertidor"/>

   8:      </Window.Resources>

   9:      <Grid>

  10:          <Grid.RowDefinitions>

  11:          <RowDefinition Height="57*" />

  12:          <RowDefinition Height="124*" />

  13:          <RowDefinition Height="521*" />

  14:          </Grid.RowDefinitions>

  15:          

  16:          <TextBlock Text="MultiBinding" FontSize="22" Grid.Row="0" HorizontalAlignment="Center"/>

  17:          

  18:          

  19:          <Slider Grid.Row="1" Margin="53,11,125,0" Name="slider1"  VerticalAlignment="Top"

  20:                  Minimum="0" Maximum="1000"

  21:                  ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Value}"/>

  22:          

  23:          <Slider Grid.Row="1" Margin="53,50,125,52" Name="slider2" Minimum="0" Maximum="1000"

  24:                  ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Value}" />

  25:          

  26:         <Slider Grid.Row="1" Height="21" Margin="53,0,125,18" 

  27:                Name="slider3" VerticalAlignment="Bottom" Minimum="0" Maximum="360" 

  28:                 ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Value}"/>

  29:          

  30:         <Image Grid.Row="2" Margin="128,81,117,175" Name="image" Stretch="Fill" Source="/TestWPF_Data_Binding_II;component/rotsnake.gif">

  31:              <Image.RenderTransform>

  32:                      <MultiBinding Converter="{StaticResource Convertidor}">

  33:                          <Binding ElementName="slider1" Path="Value"/>

  34:                          <Binding ElementName="slider2" Path="Value"/>

  35:                          <Binding ElementName="slider3" Path="Value"/>

  36:                      </MultiBinding>

  37:              </Image.RenderTransform>

  38:          </Image>

  39:   

  40:      </Grid>

  41:  </Window>



Vemos que, entre las lineas 32 y 38, se han enlazado tres propiedades de origen de enlace, las propiedades Value de tres Slider´s, para una sola propiedad destino de enlace.Además, notamos que, en la línea 33, se especifica la propiedad Converter para el MultiBinding :
Converter="{StaticResource Convertidor}"
Esto significa que el recurso estático Convertidor esta apuntando a una clase que implementa la interfaz IMultiValueConverter.En efecto, la clase se llama DoubleToRotateTransform.Ha sido instanciada en la línea 7.

En el método Convert se desarrolla la lógica de conversion de los tres valores de tipo double de la propiedad Value de cada Slider y se retorna un objeto RotateTransform, el cuál si admite la propiedad RenderTransform del objeto Image.
Es conveniente señalar que, debido a que el modo del binding es OneWay,sólo es necesario implementar el metodo Convert.

A continuación la clase DoubleToRotateTransform :


using System;
//requerido para IMultiValueConverter:
using System.Windows.Data;
//requerido para ScaleTransform:
using System.Windows.Media;
//requerido para CultureInfo culture:
using System.Globalization;

namespace TestWPF_Data_Binding_II
{
public class DoubleToRotateTransform:IMultiValueConverter
{
/// <summary>
/// Metodo que recibe dos valores de tipo double
/// y retorna un ScaleTransform
/// </summary>
/// <param name="values">Colección de dos valores de tipo double</param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns>Retorna un ScaleTransform para la prop. RenderTransform de un image</returns>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double coorX = (double)values[0], coorY = (double)values[1], angulo=(double)values[2];

RotateTransform rt = new RotateTransform(angulo,coorX, coorY);
return rt;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
//Hacer conversiones si el modo es TWOWAY
throw new NotSupportedException("No se puede convertir");
}
}
}


Como se darán cuenta, los valores de las propiedades de origen de enlace pasan al metodo Convert como una colección de objetos(primer parámetro):
objetct[] values
Además, en la colección, estan en el orden en que fueron declarados en el enlace.Así, en la posición cero esta el valor dela propiedad Value de slider1; luego, en la posicion1, slider2 y finalmente slider3.


Nota: Cada propiedad Tooltip de cada Slider esta enlazando a la propiedad Value del mismo objeto al que pertenecen(líneas 21, 24 y 28):
ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Value}"

Captura :

2 comentarios:

  1. Esta genial el ejemplo :)

    También gracias por pasar por mi blog xD

    ResponderEliminar
  2. Gracias.
    Me alegra que el ejemplo no este tan mal...

    ResponderEliminar