miércoles, 1 de agosto de 2012

Crystal Reports – Cargar imagen usando una capa de reportes


Introducción
En esta oportunidad se profundizara el trabajo de imágenes pero apuntando a Reportes, concretamente con el uso de Crystal Reports.
Para este artículo se continua con el ejemplo de uno previo:
En el anterior se listaba y editaba los datos del empleado, incluida sus fotografías, en cambio en este artículo se vera como listar en un reporte esta misma información.
El resultado del reporte final del reporte seria:
Se analizara además como incluir las imágenes provenientes de una base de datos, y también un logo tomado de un archivo de imagen.
Capa de Reportes
Esto quizás aplique un poco mejor con una arquitectura en capas, pero en este caso aunque no las haya definido del todo, se puede separa en un proyecto concreto la responsabilidad de crear los reportes.
Es por eso que se observara en la solución un proyecto de nombre ReportsLayer, este será el encargado de:
- Encapsular la diseño del reporte
- Definición y estructura de datos que requieres el reporte, en este caso implementada en dataset tipados
- La carga de la información, conectándose para ello directamente a los datos, esta capa no hará uso del DataAccess, porque al usar dataset la carga de datos se torna particular, por lo tanto su funcionalidad requiere una conexión directa.
La idea con esto es separar funcionalidad y además cubrir un defecto que tiene Crystal Reports, en donde el diseñador solo toma como entidades objetos que estén local al proyecto donde se encuentra el rpt. Muchas veces poner en la Presentación un reporte implicaría además poner allí mismo los dataset tipados, lo cual ensucia el modelo.
Definición y carga de datos en el DataSet
Para este reporte se definió un dataset tipado con dos datatable en su interior.
Para al carga de los empleados se hará uso de la funcionalidad de la clase EmpleadosDAL definida dentro del propio proyecto de Reportes.
01.internal static class EmpleadosDAL
02.{
03. 
04.internal static Empleados ObtenerTodos()
05.{
06.Empleados empleados = new Empleados();
07. 
08.using (SqlConnection conn = newSqlConnection(ConfigurationManager.ConnectionStrings["default"].ToString()))
09.{
10.conn.Open();
11. 
12.string query = @"SELECT IdEmpleado, Nombre, Apellido, FechaNacimiento, EstadoCivil, Imagen
13.FROM Empleados";
14. 
15.SqlCommand cmd = new SqlCommand(query, conn);
16. 
17.SqlDataAdapter da = new SqlDataAdapter(cmd);
18.//es necesario indicar la tabla del dataset que se quiere cargar
19.da.Fill(empleados, "Empleados");
20. 
21.}
22. 
23.return empleados;
24.}
25.}
Allí se define la consulta en donde las columnas coinciden en nombre con los definidos en timepo de diseño en el dataset tipado, además vale aclarar que la clase ha sido declarada como internal de forma intencional, para que solo la capa de Reportes pueda usar esta funcionalidad, es mas la idea es que se limite al máximo el acceso a funcionalidad que solo esta clase debería utilizar, por eso el dataset tipado también tiene el modificador de acceso asignado a internal.
Un punto adicional es la carga de una imagen externa que representa el logo de la empresa, el mismo no se encuentra en la db sino que es un archivo, es por eso que luego de cargar el reporte se observan las líneas:
1.Empleados.EmpresaRow row = empleado.Empresa.NewEmpresaRow();
2.row.Logo = ImageHelper.ImageToByteArray(ImageHelper.ObtenerImagenLogoEmpresa());
3.empleado.Empresa.Rows.Add(row);
encargadas justamente de crear una row en al datatable con la imagen del logo. En este caso se hace uso de la funcionalidad del Helper de Imágenes creado para tomar la imagen embebida como recurso.
Retorno del Reporte
Esta cada de reportes solo debería ser accedida por medio de la clase Reports con su metodo ObtenerReporteEmpleados() este devolverá la instancia del reporte con la información asignada lista para ser mostrada en pantalla, o exportada si es necesario.
01.public static class Reports
02.{
03. 
04.public static ReporteEmpleados ObtenerReporteEmpleados()
05.{
06.ReporteEmpleados report = new ReporteEmpleados();
07. 
08.//
09.// Se obtienen los datos de la lista de empleados
10.//
11.Empleados empleado = EmpleadosDAL.ObtenerTodos();
12. 
13.//
14.// Se agrega el logo de la empresa a la informacion del listado
15.//
16.Empleados.EmpresaRow row = empleado.Empresa.NewEmpresaRow();
17.row.Logo = ImageHelper.ImageToByteArray(ImageHelper.ObtenerImagenLogoEmpresa());
18.empleado.Empresa.Rows.Add(row);
19. 
20.//
21.// Se asigna los datos a la instancia del reporte
22.//
23.report.SetDataSource(empleado);
24. 
25.return report;
26.}
27. 
28.}
Lanzar el Reporte en al Presentación
El ultimo punto por tratar es como se usara lo anteriormente explicado desde la presentación.
Por un lado contamos con un formulario especialmente creado para desplegar el reporte, el mismo solo cuanta con el CrystalReportViewer y recibe por parámetro la instancia del reporte que debe mostrar.
01.public partial class Reporte : Form
02.{
03.private ReportClass _report = null;
04. 
05.public Reporte()
06.{
07.InitializeComponent();
08.}
09. 
10.public Reporte(ReportClass report)
11.:this()
12.{
13._report = report;
14.}
15. 
16.private void Reporte_Load(object sender, EventArgs e)
17.{
18.crystalReportViewer1.ReportSource = _report;
19.}
20.}
Se define un nuevo constructor del formulario para pasar la instancia del reporte al formulario y es en el Load del mismo que se asigna al Viewer, para desplegar el reporte en pantalla.
Por otro lado tenemos un botón en la pantalla de ListaEmpleados, el cual recupera el reporte, con los datos asignados, y se la pasa a la instancia del formulario para que la muestre en pantalla.
01.private void btnListar_Click(object sender, EventArgs e)
02.{
03. 
04.ReporteEmpleados report = Reports.ObtenerReporteEmpleados();
05. 
06.Reporte frmReporte = new Reporte(report);
07.frmReporte.Show();
08. 
09.}

Código de ejemplo
La base de datos utilizada en el ejemplo es la Sql Server Express 2008 R2, como ver en la solución el mdf esta integrado al Visual Studio, por lo tanto con solo tener el sql server express instado esta debería funciona adjuntándose sola al servicio.
En la carpeta “script” del proyecto “DataAccess”  se encuentra un archivo .sql con las instrucciones para crear la estructura de tablas y datos que se requieren para este articulo.

[C#]
[VB.NET]

No hay comentarios:

Publicar un comentario