[WPF] Data Templates

Hola buenas!

Estáis deseosos de aprender más maravillas de WPF, ¿verdad? Pues nada, aquí os traigo algo muy util que os podría venir bien para vuestros propios desarrollos.

Empezamos con la gran pregunta:

¿Qué son los Data Templates?

Imagina que tienes una clase llamada Persona, Animales, etc. y queréis representar instancias de dichas clases visualmente en vuestro programa, el problema como ya sabes es que dichas clases no tienen ninguna representación visual, con lo cual el resultado de ligar una instancia (o una lista de instancias) a un control como por ejemplo un ItemsControl sería el de llamar al método ToString de la instancia lo que nos da un resultado pésimo.

¿Qué podemos al respecto? Pues lo que estabas pensando si, usar Data Templates.

¡Al turrón!

Creamos un nuevo proyecto llamado Data Templates y creamos una clase llamada Personas, dicha clase contendrá este código:

public class Persona
{
    public string Nombre {get; set; }
    public string Direccion { get; set; }
    public string Telefono { get; set; }
    public int Edad { get; set; }
    public string Sexo { get; set; }
    public string UrlImagen { get; set; }
    public string Color { get; set; }

    public Persona(string nombre, string direccion, string telefono,
                    int edad, string sexo)
    {
        Nombre = nombre;
        Direccion = direccion;
        Telefono = telefono;
        Edad = edad;
        Sexo = sexo;

        if (Sexo.Equals("Hombre"))
        {
            Color = "#bcebf9";
            UrlImagen = "Imagenes\\hombre.png";
        }
        else
        {
            Color = "#f8c2cd";
            UrlImagen = "Imagenes\\mujer.png";
        }
    }

    public override string ToString()
    {
        return string.Format("Hola me llamo {0}, vivo en {1}, mi telefono es {2}, tengo {3} años y soy {4}", Nombre, Direccion, Telefono, Edad, Sexo);
    }
}

Nada aquí que os vaya a sorprender, una clase Persona, que aunque bastante mejorable, va de sobra para nuestro ejemplo. Puntualizo un par de cosas:

Ignorad por ahora el tema de las imagenes y el color, eso se usará más adelante (también meteremos las imagenes más adelante en el proyecto)
El método ToString solo es para ver como quedaría la cosa sin Data Templates y luego se borrará.

Ahora creamos una clase llamada Presenter y le añadimos el siguiente código:

class Presenter
{
    private List<Persona> listaPersonas;

    public Presenter()
    {
        listaPersonas = new List<Persona>();

        listaPersonas.Add(new Persona("Jesus", "Calle 13", "132456789", 23, "Hombre"));
        listaPersonas.Add(new Persona("Rosi", "Big street 15", "987654321", 27, "Mujer"));
        listaPersonas.Add(new Persona("Álvaro", "To lejos street", "147258369", 24, "Hombre"));
    }

    public List<Persona> ListaPersonas
    {
        get { return listaPersonas; }
        set { listaPersonas = value; }
    }
}

Una clase normal y corriente, simplemente creamos una lista de personas y añadimos algunos ejemplos de personas.

Ahora abrimos el code-behind de la ventana (Windows1.xaml) y modificamos el constructor para que quede de esta manera:

public Window1()
{
    InitializeComponent();
    DataContext = new Presenter();
}

Y ahora, abrimos la ventana en sí y colocamos este markup:

<Window x:Class="DataTemplates.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Data Templates" Height="600" Width="600">
    <ItemsControl ItemsSource="{Binding ListaPersonas}">

    </ItemsControl>
</Window>

Aquí simplemente añadimos un ItemsControl vacío al que le ligamos la lista que hemos creado anteriormente.

Ahora ejecutamos la aplicación y vemos el resultado:

Como podeis ver, apesta, es lo más cutre “ever seen”, así que vamos a arreglarlo usando los Data Templates.

Antes que nada, me gustaría explicar una cosilla para que no os lieis tanto:

Hay 2 clases bases para los controles, por un lado tenemos la clase ContentControl de la cual heredarán aquellos controles que solo tienen una pieza de contenido, como button, Label, etc.
Por otro lado tenemos la clase ItemsControl de la cual heredarán aquellos controles que muestran una colección de items, como TreeView, ListBox, etc.

Si con la funcionalidad básica que nos ofrecen dichas clases bases vamos bien, no tenemos por qué usar ninguna hija, y en este caso como habeis visto, hemos usado simplemente un ItemsControl pues es todo lo que necesitamos.

Bueno, al grano, si queremos usar los Data Templates, lo unico que debemos hacer es decirle al control, en este caso el ItemsControl, que vamos a definir el aspecto de cada item del control, ¿Cómo? Así:

<ItemsControl ItemsSource="{Binding ListaPersonas}">
    <ItemsControl.ItemTemplate>
		<DataTemplate>
			...
		</DataTemplate>
	</ItemsControl.ItemTemplate>
</ItemsControl>

Ahí, donde están los puntos suspensivos pues añadimos todo el xaml necesario para lograr el aspecto que queramos. Recordad que estamos definiendo el aspecto de UN solo item y no de toda la colección a la vez, así que ahi escribimos como queremos que se vea cada item y ya se aplicará para todos los items de la lista.

Así que sabiendo esto, vamos a modificar nuestro ejemplo.

Para empezar, puedes borrar el ToString de la clase Personas que ya no nos vale, una vez hecho esto, creamos el directorio Imagenes dentro del proyecto y ahi metemos las dos imágenes que voy a adjuntar a continuación (boton derecho -> guardar como):

[Imagen hombre]

[Imagen mujer]

Ya lo único que nos queda es modificar el ItemsControl añadiendole el template de cómo queremos que se represente cada instancia de la clase.

El código de la ventana quedaría así:

<Window x:Class="DataTemplates.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Data Templates" Height="600" Width="600"
    Background="#f8fffb">
    <ItemsControl ItemsSource="{Binding ListaPersonas}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="#4f9d70" BorderThickness="2"
                        Margin="5" Padding="2.5">
                    <Grid Background="{Binding Color}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto" />
                            <RowDefinition Height="auto" />
                            <RowDefinition Height="auto" />
                            <RowDefinition Height="auto" />
                        </Grid.RowDefinitions>
                        <Border BorderBrush="#4f9d70"  BorderThickness="1"
                                Margin="2.5" Grid.RowSpan="4">
                            <Image Source="{Binding UrlImagen}" />
                        </Border>
                        <TextBlock Text="Nombre: " FontSize="20" FontWeight="Bold" Grid.Column="1" />
                        <TextBlock Text="{Binding Nombre}" FontSize="20" Grid.Column="2" />

                        <TextBlock Text="Dirección: " FontSize="20" FontWeight="Bold" Grid.Column="1" Grid.Row="1" />
                        <TextBlock Text="{Binding Direccion}" FontSize="20" Grid.Column="2" Grid.Row="1" />

                        <TextBlock Text="Teléfono: " FontSize="20" FontWeight="Bold" Grid.Column="1" Grid.Row="2" />
                        <TextBlock Text="{Binding Telefono}" FontSize="20" Grid.Column="2" Grid.Row="2" />

                        <TextBlock Text="Edad: " FontSize="20" FontWeight="Bold" Grid.Column="1" Grid.Row="3" />
                        <TextBlock Text="{Binding Edad}" FontSize="20" Grid.Column="2" Grid.Row="3" />
                    </Grid>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>

Bueno, aunque os de miedo al principio, el código es bastante facilón.

Añadimos un borde y dentro pues un grid y dentro de dicho grid colocamos los controles para representar los datos.

Aquí muy importante decir, que el DataContext dentro del DataTemplate será la instancia del objeto con el que estamos tratando, así que por ejemplo:

<TextBlock Text="{Binding Nombre}" FontSize="20" Grid.Column="2" />

Aqui con Nombre no nos estamos refiriendo a una propiedad llamada Nombre dentro de Presenter (el DataContext de la ventana), si no a la propiedad Nombre de las instancias de Persona que tiene la lista.

Ahora estáis viendo el uso que le doy a la propiedad Color dentro de la clase Persona, lo uso para definir el color de fondo del item. Sé que no debería añadir esta propiedad dentro de la clase, pero lo hago con motivos ilustrativos simplemente.

Creo que aquí no hay más nada que requiera de una explicación, aunque si os dejaré una screenshot para aquellos que no estén escribiendo el ejemplo en sus ordenadores.

Bueno, creo que no se me olvida nada, ahora solo queda esperar vuestros comentarios para ver que os ha parecido el artículo.

Os adjunto el proyecto : DataTemplates.rar

1 comentario so far »

  1. Datos en tiempo de diseño (Design DataContext) « El Blog de Fox said,

    Wrote on Diciembre 9, 2009 @ 16:13

    [...] Para seguir este artículo necesitaréis de Microsoft Expression Blend 3 o Visual Studio 2010 Beta 2 por las razones que describiré más adelante. Además necesitaréis una copia del proyecto del artículo “Data Templates“. [...]

Comment RSS · TrackBack URI

Dejar un comentario

Nombre: (Required)

E-mail: (Required)

Website:

Comment: