8.02.2010

Presentando Imágenes y Texto en un ComboBox en WPF

Cuando realizamos proyectos en WFP, es común tener que hacer que la aplicación sea lo más visual posible para el usuario final, esto por que cuando una empresa decide moverse de windows Forms a WPF normalmente lo hace por que quiere aprovecharse de todas las bondades visuales de XAML y WPF para hacer lucir sus aplicaciones espectaculares. En este post vamos a ver como desplegar una imagen dentro de un combo box, y además le vamos a agregar una descripción a esta imagen en el mismo control.

Detalle de la Solución

En este caso vamos a crear una pantalla muy simple en donde vamos a pone un combo box, para que el usuario seleccione el empleado que desea. Al mismo tiempo vamos a desplegar el nombre y los apellidos del empleado seleccionado en la parte inferior del combo box.

Solución #1: Imágenes en el Path

La primera solución que vamos a plantear es tener las imágenes un directorio en el disco duro de la máquina, y en el registro del empleado, vamos a poner el nombre de la imagen que posee. Esta solución es la mas simple sin embargo tiene sus contras, por ejemplo con esta opción es imposible garantizar la integridad referencial de los datos, ya que si se elimina el registro no se puede garantizar el eliminado de la foto en el directorio – entre otras cosas.

Para iniciar, vamos a conseguir las imagenes de los empleados que vamos a tener disponibles en el combo, yo en mi caso busque imagenes de caricatura en Bing->Images y las agregue a un directorio que hice en mi proyecto para tener las imagenes disponibles. La siguiente imágen muestra el agregado de las fotos del usuario y su ubicación en el proyecto

image

image

Seguidamente procedemos a crear la base de datos donde vamos a guardar los datos del empleado, para este le damos al proyecto agregar nuevo ítem y procedemos a agregar una base de datos local la cual llamaremos PeopleDB.sdf como se ve en la siguiente imagen.

image

Luego creamos una tabla en la base de datos utilizando el Database Explorer de VS2010 – funciona igual en VS2008 -

image

En la tabla vamos a crear los siguientes campos.

image

Ahora procedemos a agregarle campos de forma manual utilizando el database explorer en la opción “Show Table Data”. Como podemos ver, hemos puesto la ruta de las fotos como “Images\<Nombre Foto>”

image

Seguidamente vamos a crear una clase que me permita representar cada uno de los empleados con los que voy a interactuar, para así poder crear una clase de lógica de negocios que me permita obtener los datos del empleado. – en este caso estamos creando la clase de entidades, de acceso a datos y de negocios en el mismo proyecto, pero como se puede leer en posts anteriores, lo recomendable es tener librerías para cada una de estas capas.

La capa de entidades tiene cada una de las propiedades automáticas para almacenar cada uno de los valores de los campos de la tabla especificada enteriormente.

image

Seguidamente procedemos a construir la clase para el acceso a datos. Esta clase se presenta  a continuación

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlServerCe;
using System.Data;

namespace WPFTricks
{
public static class Empleado_DAL
{

static string dbFile = @"Data Source=PeopleDB.sdf";

public static List<Empleado> ObtenerEmpleados()
{
List<Empleado> empleados = new List<Empleado>();
try
{
using (SqlCeConnection connection = new SqlCeConnection(dbFile))
{
SqlCeCommand command = new SqlCeCommand("SELECT * FROM Empleados", connection);
connection.Open();
IDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Empleado emp = new Empleado();

emp.Id = System.Convert.ToInt32(reader["Id"]);
emp.Nombre = reader["Nombre"].ToString();
emp.Apellido1 = reader["Apellido1"].ToString();
emp.Apellido2 = reader["Apellido2"].ToString();
emp.Direccion = reader["Direccion"].ToString();
emp.Email = reader["Email"].ToString();
emp.FotoUrl = reader["Imagen"].ToString();

empleados.Add(emp);
}
}
}
catch (Exception ex)
{
throw ex;
}
return empleados;
}
}
}



Como se puede ver en el código anterior, tenemos un método que devuelve todos los empleados almacenados en la tabla empleados. Algo a señalar es que el connection string utilizado es de la forma static string dbFile = @"Data Source=PeopleDB.sdf";  el cual es de esta forma, porque nuestra base de datos tiene modificada la propiedad “Copy to Output Directory” tal y como se ve en la siguiente figura. En este caso el valor de esta propiedad ha sido cambiado a “Copy Always” con lo cual la base de datos se copia al directorio de salida de compilación, por lo que la base de datos residirá en el mismo directorio que el ejecutable y las librerías de nuestra aplicación demo.



image



Ahora el siguiente paso es crear la lógica de negocios, la cual se muestra a continuación:



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WPFTricks
{
public class Empleado_BL
{
public List<Empleado> ObtenerEmpleados()
{
return Empleado_DAL.ObtenerEmpleados();
}
}
}



Esta clase es bastante simple, ya que por la naturaleza de nuestro demo, el único método que vamos a tener en la clase es el que retorna la lista de empleados desde la capa de acceso a datos, y al ser los métodos del DAL estáticos, lo único que tenemos que hacer es invocar y retornar el resultado de la invocación del método ObtenerEmpleados.



A nivel de UI si vamos a tener un combobox en donde vamos a desplegar el nombre y la foto de nuestro empleado. En modo diseño así es como luce nuestra pantalla:



image



El código para cargar el ComboBox es bastante simple y ya lo hemos visto en varios post anteriores de WPF, por lo que esta vez lo vamos a poner pero no lo vamos a comentar:



public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}


private void Window_Loaded(object sender, RoutedEventArgs e)
{
Empleado_BL empleado = new Empleado_BL();
List<Empleado> lista = empleado.ObtenerEmpleados();
cmbEmpleados.ItemsSource = lista;
}
}



El código donde esta el truco es en el código XAML. El código se puede ver a continuación:



<Window x:Class="WPFTricks.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="383" Width="659" Loaded="Window_Loaded">
<
Grid>
<
ComboBox ItemsSource="{Binding}" Height="40" HorizontalAlignment="Left" Margin="56,49,0,0" Name="cmbEmpleados" VerticalAlignment="Top" Width="215" >
<
ComboBox.ItemTemplate>
<
DataTemplate>
<
Grid>
<
Grid.ColumnDefinitions>
<
ColumnDefinition></ColumnDefinition>
<
ColumnDefinition></ColumnDefinition>
</
Grid.ColumnDefinitions>
<
Label Content="{Binding Path=Nombre}" Grid.Column="1" Height="28" HorizontalAlignment="Left" Margin="10,10,0,0" Name="label1" VerticalAlignment="Top" />
<
Image Source="{Binding Path=FotoUrl}" Grid.Column="0" Height="40" Width="40" Stretch="Fill"></Image>
</
Grid>
</
DataTemplate>
</
ComboBox.ItemTemplate>
</
ComboBox>

</
Grid>
</
Window>



En este caso, lo importante esta en el ItemTemplate. Esta clase nos permite personalizar la manera en que se van a desplegar los ítems en el combo. El Ítem template permite asignar un DataTemplate, el cual describe la estructura visual de un elemento dentro de un control en WPF, esto cuando se hace una operación de binding a un ItemsSource. En este caso, vamos a agregar un Grid en el DataTemplate, luego vamos a agregar dos columnas por cada ítem, en la primera columna vamos a poner la foto, y en la segunda columna el nombre del empleado; para lograr esto definimos dentro del DataTemplate los controles antes mencionados y procedemos a indicar en cual columna se deben de ubicar utilizando el propiedad Grid.Column. Por último hacemos el binding directo a los campos de la clase, por lo que aunque los campos tenga otro nombre en la tabla, lo importante en este caso es el nombre de las propiedades que lo representan en el objeto, en nuestro caso, FotoUrl y Nombre. El resultado al ejecutar el demo anterior es el siguiente:



image



Si seleccionamos uno de los elementos, el ítem seleccionado se ve de la siguiente manera:



image



Technorati Tags: ,,

3 comentarios:

Anónimo dijo...

eso es justamente lo que queria saber sobre cargar imagenes en el combo en WPF pero como seria en lenguaje visualbasic.net? la verdad no se si me podrian ayudar :)
les dejo mi correo "electroman1392@hotmail.com"

Ricardo.Bohorquez dijo...

disculpa xp es q pones en los using System.Data.SqlServerCe;... le agregaste alguna referencia??

Anónimo dijo...

Como hago para Agregarle un valor que no sea el texto que muestra y como hago para obtener esos valores?