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 Class
Conclusió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.
|