Creación de PDF desde VS.Net sin componentes de terceros
Fecha: 12/Ene/2006 (11-01-06)
|
INTRODUCCION:
Con el paso del tiempo, las aplicaciones que desarrollamos necesitan de mayor dedicación para cumplir con los requerimientos de los usuarios. Esto provoca que en algunas ocasiones tengamos ciertos problemas para satisfacer a nuestros queridos clientes "Los Usuarios" que son la razón de ser de nuestro trabajo. Estos esfuerzos por mantenerlos contentos, se ven mermados por la imposibilidad (sea técnica o de herramientas) de mostrar una data en un formato determinado. Este es el caso de los famosos Documentos de Formato portátil (PDF) que tanto les gustan a los usuarios (Y a nosotros mismo). No hace mucho tiempo tuve el inconveniente, de que un usuario deseaba mantener los datos que le mostraba en un datagrid en un archivo. El problema comenzó cuando deseaba que como primera opción le enviara el archivo en un .PDF, cosa que no tenia idea de como lograrlo. En segundo lugar me ha propuesto que se lo envié en un documento de Word. Es decir, que la información que le mostraba en un DataGrid en una pagina, se la transformara en un documento de Word y se la enviara. Al igual que la anterior opción, no tenía dominio de tema para complacerlo. En ese caso, opté por terminar enviándole el DataGrid por correo a sugerencia de un amigo (mi colega de código, Andrés Faya) y es así como he salido de paso. Luego me he encontrado un artículo que escribió alguien para www.elguille.info para generar PDF desde .net. La idea me atrajo y me he leído el artículo y le he escrito al autor, he consultado el site que tiene como referencia para descargar el componente extra que necesito (no nativo de vs.net) y al final de cuentas no he conseguido lo que he deseado. Esta situación, gracias a vs.net ha llegado a su final, pues nuestro IDE cuenta con las herramientas necesarias para crear nuestros PDF sin tener que usar componentes ni códigos de terceros. Este artículo, no pretende volverlos unos expertos en la creación de archivos de extensión PDF, pero por lo menos les mostrará la luz para continúen por ustedes mismos explorando y de paso compartiendo los conocimientos que adquieran (que no se les olvide esa parte, pues es la única forma en que podemos crecer como comunidad .net).
Desarrollo:
Bien, lo primero que necesitamos hacer es crear un reporte con Crystal Report que nos proporcione la apariencia que deseamos en nuestro .PDF. Se preguntaran, porque un reporte con Crystal? La respuesta es sencilla, la información que vamos a cargar en nuestro PDF, es la información que le estamos mostrando a nuestros usuarios en un datagrid y por ende, quien mejor que Crystal para darle un buen formato a ese reporte que deseamos convertir a PDF. Recuerden que con crystal puedes diseñar cartas y no solo reportes como tal. El fundamento de este ejemplo está sustentado en la creación de un DataSet tipado con el esquema de los campos que vamos a mostrar en nuestro PDF. Una vez hecho esto, entonces procedemos con las funciones que nos permiten crear nuestro PDF. Cuerpo de código
Imports CrystalDecisions.CrystalReports.Engine Imports System.Data.SqlClient Public Class Form1 Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code " Public Sub New() MyBase.New() 'This call is required by the Windows Form Designer. InitializeComponent() 'Add any initialization after the InitializeComponent() call End Sub 'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub 'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer 'NOTE: The following procedure is required by the Windows Form Designer 'It can be modified using the Windows Form Designer. 'Do not modify it using the code editor. Friend WithEvents Button1 As System.Windows.Forms.Button Friend WithEvents mconn As System.Data.SqlClient.SqlConnection <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() Me.Button1 = New System.Windows.Forms.Button Me.mconn = New System.Data.SqlClient.SqlConnection Me.SuspendLayout() ' 'Button1 ' Me.Button1.Location = New System.Drawing.Point(344, 264) Me.Button1.Name = "Button1" Me.Button1.TabIndex = 1 Me.Button1.Text = "Button1" ' 'mconn ' Me.mconn.ConnectionString = "workstation id=U24603;packet size=4096;integrated security=SSPI;data source=U2460" & _ "3;persist security info=False;initial catalog=TimeManager" ' 'Form1 ' Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(432, 318) Me.Controls.Add(Me.Button1) Me.Name = "Form1" Me.Text = "Form1" Me.ResumeLayout(False) End Sub #End Region Private Function CrearPDF(ByVal ds As DataSet) Dim strpdf As String 'Esta es la instancia del reporte que tengo hecho con un binding del dataset tipado Dim cr As New Bloqueos cr.SetDataSource(ds) Try 'En la siguiente línea determinamos el formato final del reporte. cr.ExportOptions.ExportFormatType = CrystalDecisions.[Shared].ExportFormatType.PortableDocFormat Dim filedest As New CrystalDecisions.Shared.DiskFileDestinationOptions 'Determinamos la ruta donde se va a crear nuestro archivo al finalizar el proceso en este caso, 'concatenamos horas, minutos, segundos, para mantener control en caso de usar la misma ruta en otras instancias. Dim nombrearchivopdf As String = "C:\pdf\PDF" & Date.Now.Hour & Date.Now.Minute & Date.Now.Second & ".pdf" filedest.DiskFileName = nombrearchivopdf 'Le pasamos al reporte el parámetro destino del reporte (ruta) cr.ExportOptions.DestinationOptions = filedest 'Le indicamos que el reporte no es para mostrarse en pantalla, sino, que es para guardar en disco cr.ExportOptions.ExportDestinationType = CrystalDecisions.[Shared].ExportDestinationType.DiskFile 'Indicamos el formato de la página del reporte cr.PrintOptions.PaperOrientation = CrystalDecisions.[Shared].PaperOrientation.Landscape 'Finalmente exportamos el reporte a PDF cr.Export() 'Como buenos samaritanos nos curamos en salud, y atrapamos las posibles excepciones que se pudieran presentar. Catch ex3 As CrystalDecisions.CrystalReports.Engine.InternalException MsgBox(ex3.Message & " -----" & ex3.StackTrace) Catch ex2 As CrystalDecisions.CrystalReports.Engine.ExportException MsgBox("Se ha producido un error cargando los archivos a PDF. Error: " & ex2.Message, MsgBoxStyle.Information, "PDF Creator") Catch ex As System.IO.IOException MsgBox("Se ha producido un error cargando los archivos a PDF. Error: " & ex.Message, MsgBoxStyle.Information, "PDF Creator") End Try End Function Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim ad As New SqlDataAdapter("select * from bloqueotiempo", mconn) Dim ds2 As New ds Dim dt As New DataTable 'Copiamos el esquema del DataSet tipado que hemos creado. "Ojo" no estamos copiando 'los registros que representa, solo la estructura. Pues, para copiar el contenido es con el método copy dt = ds2.Tables(0).Clone Try mconn.Open() ad.Fill(dt) Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.Information, "Prueba") Finally mconn.Close() End Try Dim i As Int32 Dim con As Int32 Dim dat As Date 'Debido a que en este caso vamos a retornar un PDF por registros, entonces limpiamos 'el DataSet tipado para que solo contenga el registro correspondiente a un pdf a la hora de llamar la función que los crea ds2.Tables(0).Clear() 'Creamos un dataRow con el esquema de un row del dataset tipado para luego agregarle esta fila con datos al mismo dataset Dim row2 As DataRow = ds2.Tables(0).NewRow 'Hacemos el recorrido de los registros For i = 0 To dt.Rows.Count - 1 'Esta parte es fundamental que se realice de esta manera, pues en lo personal no he logrado pasar datos entre datarow directamente. con = dt.Rows(i)(0) row2(0) = con dat = dt.Rows(i)(1) row2(1) = dat dat = dt.Rows(i)(2) row2(2) = dat con = dt.Rows(i)(3) row2(3) = con con = dt.Rows(i)(4) row2(4) = con 'Agrego la fila llena con los datos para crear el pdf al dataset tipado ds2.Tables(0).Rows.Add(row2) 'Paso el dataset tipado como parámetro a la función que me genera el pdf CrearPDF(ds2) 'Limpio el dataset para que la próxima iteración solo contenga el próximo registro ds2.Tables(0).Clear() Next End Sub End ClassConclusión:
Como pudieron observar, no ha sido necesaria la inclusión de ningún componente extra, para generar el PDF. Esto trae como consecuencia, que podamos crear aplicaciones Sin depender de las limitaciones que nos impongan terceros con sus componentes. Con esto y al igual que el los artículos anteriores espero que les sirva de ayuda a los que necesitan el conocimiento referente a la generación de PDF, que en honor a la verdad se que muchos son. Pues hasta hace poco era parte del conglomerado. Espero que les sirva y contribuya en su crecimientos como desarrolladores.