Informe en .NET con Crystal Reports y base de datos MySQL.

Vaya por delante que el tema de la creación de informes (o reports) siempre ha sido una de las partes de la programación que me ha dado más pereza. Pero está claro que pocas aplicaciones se salvan de requerirlos en mayor o menor grado, y la que actualmente tengo entre manos no es, en absoluto, una excepción. Así pues, estos últimos días he tenido que preparar un nuevo report y de paso he aprovechado para investigar un poco y descubrir una nueva manera de realizarlos. Paso a explicarme.

Como ya he comentado en ocasiones, mi entorno de desarrollo es VisualBasic.NET y una base de datos MySQL. Y los informes los hago con el propio Crystal Reports que incorpora el VisualStudio.NET. El tema está en que hasta ahora los hacía a través de una conexión ODBC que tenía que instalar en cada máquina apuntando hacia el servidor MySQL, pero este sistema no me gustaba demasiado. Y no me gustaba porque en realidad de bases de datos tengo distintas con distintos nombres pero con las mismas estructuras de tablas y datos parecidos, ya que una es la productiva (la real, la buena) y las otras son para desarrollo, para que los usuarios hagan pruebas sin que afecte a los datos reales, etc. Controlar la cadena de conexión en la aplicación para que ataque a una u otra base de datos no me supone el más mínimo problema, pero los informes cogen sus datos a través de una conexión ODBC concreta y ésta en cada máquina ataca a una única base de datos. Así que no me convence este sistema.

Y ahora he descubierto cómo puede crear informes a través de un DataTable y de una estructura en un archivo XML, sin necesidad de nada más. De hecho en lugar de un DataTable se puede utilizar perfectamente un DataSet y funciona sin ningún tipo de problemas ni apenas modificaciones (dejo en manos del lector probarlo si le interesa). Voy a pasar a explicar mediante un ejemplo y algunas imágenes cómo realizarlo desde cero.

Partiré de dos tables en mi base de datos MySQL en las que guardaré información de facturas. La primera tabla es de cabeceras de esas facturas y tiene estos datos:

+---------+------------+-------------------------+
| blh_num | blh_dat    | blh_cus                 |
+---------+------------+-------------------------+
|       1 | 2008-07-30 | CERAMICAS PEPE, S.A.    |
|       2 | 2008-07-30 | TALLERES GOMEZ, S.L.    |
|       3 | 2008-07-31 | DEPORTES DAMIAN, S.L.   |
|       4 | 2008-07-31 | SOFTWARE ALBERTMATA.NET |
+---------+------------+-------------------------+

La segunda tabla son las posiciones de cada factura y tiene estos otros datos:

+---------+---------+------------------------+---------+---------+
| blp_num | blp_pos | blp_art                | blp_pri | blp_qty |
+---------+---------+------------------------+---------+---------+
|       1 |       1 | RATON LOGITECH         |   15.95 |       1 |
|       2 |       1 | MONITOR LG 19 PULGADAS |   210.5 |       1 |
|       3 |       1 | ROUTER DLINK           |      56 |       1 |
|       4 |       1 | RATON LOGITECH         |   15.95 |       2 |
|       4 |       2 | TECLADO LOGITECH       |   12.95 |       1 |
|       4 |       3 | RECEPTOR GPS ZAPPA     |   59.95 |       1 |
|       4 |       4 | PAQUETE 500 FOLIOS     |     3.7 |       4 |
+---------+---------+------------------------+---------+---------+

Es algo muy sencillo y poco normalizado, pero nos servirá para el ejemplo. Concretamente vamos a crear un informe que será nada más que una impresión de una factura. Como voy a trabajar con un simple DataTable pero mi informe requerirá datos de dos tablas, me crearé primero una vista en MySQL con la siguiente instrucción:

CREATE VIEW zbl_bill2print AS 
(
SELECT
    blh_num AS BILL_NUMBER,
    blh_dat AS BILL_DATE,
    blh_cus AS BILL_CUSTOMER,
    blp_pos AS LINE_NUMBER,
    blp_art AS LINE_ARTICLE,
    blp_pri AS LINE_UNITPRICE,
    blp_qty AS LINE_UNITS,
    blp_pri * blp_qty AS LINE_TOTALPRICE
FROM
    blh_billheader LEFT JOIN blp_billposits ON blh_num = blp_num
WHERE
    blh_num = 4
);

Así, mi informe a partir de ahora se realizará sobre esta vista zbl_bill2print. Vamos pues a empezar con la parte que incumbe a .NET.

Paso 1. Creación del archivo XML con la estructura de la tabla/vista.

Para todo el ejemplo jugaremos con:

1) un formulario frmMain donde tendremos el objeto visualizador de informes.
2) una clase clsReportCreator que crearemos a continuación.
3) un informe rptBill que representará la factura que queremos imprimir.

Comenzamos pues creando la clase clsReportCreator, que constará de un único atributo (el nombre de la tabla o vista), un método constructor, un método para cargar el DataTable correspondiente y un último método para generar el archivo XML. El código completo de esta clase es el siguiente:

'--------------------------------------------------------------------
' Author:      Albert Mata (www.albertmata.net)
' Date:        20080731
' Needs:       MySQL.Data reference.
' Description: Class to create a report using just an XML file. 
'--------------------------------------------------------------------
Imports MySql.Data.MySqlClient

Public Class clsReportCreator

    '----------------------------------------------------------------
    ' Attributes.
    '----------------------------------------------------------------
    Private TableOrView As String

    '----------------------------------------------------------------
    ' Constructor method.
    '----------------------------------------------------------------
    Public Sub New(ByVal TableOrView As String)
        Me.TableOrView = TableOrView
    End Sub

    '----------------------------------------------------------------
    ' Returns DataTable corresponding to TableOrView.
    '----------------------------------------------------------------
    Public Function GetDataTable() As DataTable
        Dim DA As MySqlDataAdapter
        Dim DS As New DataSet
        Dim DT As DataTable
        Dim ConnectionString As String
        Dim SQL As String

        'Setting connection string to connect to MySQL database.
        ConnectionString = "Database = blog; " _
                         & "Data Source = localhost; " _
                         & "User ID = root; " _
                         & "Password = mypassword"

        'Setting SQL string.
        SQL = "SELECT * FROM " & Me.TableOrView

        'Getting data and filling DataSet and DataTable.
        DA = New MySqlDataAdapter(SQL, ConnectionString)
        DA.Fill(DS, Me.TableOrView)
        DT = DS.Tables(Me.TableOrView)

        'Returning DataTable.
        Return DT
    End Function

    '----------------------------------------------------------------
    ' Creates XML file in desired path.
    '----------------------------------------------------------------
    Public Sub CreateXMLFile(ByVal FilePath As String)
        Dim DT As DataTable

        'Creating DataTable.
        DT = Me.GetDataTable()

        'Writting XML file in desired path.
        DT.WriteXmlSchema(FilePath & Me.TableOrView & ".xml")
    End Sub

End Class

Y creamos también el formulario frmMain cuyo único código por el momento (después cambiará un poco) será el que sigue:

'--------------------------------------------------------------------
' Author:      Albert Mata (www.albertmata.net)
' Date:        20080731
' Description: Form to show how to create a report using just an XML
'              file. 
'--------------------------------------------------------------------
Public Class frmMain

    '----------------------------------------------------------------
    ' As a first step, creates XML file.
    '----------------------------------------------------------------
    Private Sub frmMain_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
       'Creating XML file.
        Dim RC As New clsReportCreator("zbl_bill2print")
        RC.CreateXMLFile("C:\")
    End Sub

End Class

Con esto tenemos una primera aplicación que al ejecutarla nos creará el archivo C:\zbl_bill2print.xml con la estructura de la vista zbl_bill2print. Lo probamos pues y obtenemos un archivo como éste.

Paso 2. Creación del informe e inserción del origen de datos.

Añadimos al proyecto un informe al que llamaremos rptBill.rpt y que crearemos seleccionando la alternativa Como informe en blanco y por tanto desestimando plantillas.

A continuación en el menú Explorador de campos seleccionamos la primera opción Campos de base de datos y en su menú contextual hacemos click en la opción Asistente de base de datos.

En el menú que se despliega (Orígenes de datos disponibles) seleccionamos Crear nueva conexión y a continuación la opción ADO.NET.

Con esto se nos abrira un nuevo formulario en el que nos solicitará la Ruta del archivo. Debemos aquí ir a buscar el archivo XML que hemos creado anteriormente (en mi caso el C:\zbl_bill2print.xml) y acto seguido pulsar en Finalizar. Con ello, en el menú anterior (Orígenes de datos disponibles) se nos mostrará ya la opción NewDataSet incluyendo el zbl_bill2print que acabamos de añadir.

Lo marcamos y le damos al botón para trasladarlo al menú de Tablas seleccionadas y pulsamos en Aceptar.

Con esto hemos conseguido que en el menú Explorador de campos nos aparezca ya la estructura de zbl_bill2print con sus campos, tal como se muestra a continuación:

Paso 3. Diseño del informe.

No tiene ningún misterio. Se trata de añadir los campos desde el menú Explorador de campos donde corresponda, insertarle los objetos de texto que nos parezcan adecuados, los totales cuando sea preciso, dar formato a los textos, incorporar imágenes y demás florituras a nuestro antojo...

Yo me inclino por un diseño sobrio como éste:

Paso 4. Últimos pasos para obtener la factura.

Por último vamos ya a crear la factura. Para ello en el formulario frmMain añadiremos un objeto de tipo CrystalReportViewer al que llamaremos por ejemplo crvBill. Y modificamos el código de frmMain para dejarlo como sigue:

'--------------------------------------------------------------------
' Author:      Albert Mata (www.albertmata.net)
' Date:        20080731
' Description: Form to show how to create a report using just an XML
'              file. 
'--------------------------------------------------------------------
Imports CrystalDecisions.CrystalReports.Engine

Public Class frmMain

    '----------------------------------------------------------------
    ' Creates XML file (just once) and creates and loads a report.
    '----------------------------------------------------------------
    Private Sub frmMain_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
        'Creating XML file.
        Dim RC As New clsReportCreator("zbl_bill2print")
        'RC.CreateXMLFile("C:\")

        'Creating report.
        Dim RD As ReportDocument = New rptBill()

        'Setting data source for report.
        Dim DT As DataTable = RC.GetDataTable()
        RD.SetDataSource(DT)

        'Setting data source for possible subreports.
        For Each SR As ReportDocument In RD.Subreports
            If SR.Database.Tables.Count > 0 Then
                SR.SetDataSource(DT)
            End If
        Next

        'Setting recently created report must be shown in viewer.
        Me.crvBill.ReportSource = RD
    End Sub

End Class

Nótese que ahora ya he comentado la línea en que creamos el archivo XML, puesto que sólo necesitamos crearlo una única vez para luego poder generar el origen de datos, pero a partir de aquí no necesitaremos andar creándolo cada vez.

En este código lo que estamos haciendo fundamentalmente es crear un objeto del tipo informe que hemos diseñado en el paso 3, obtener un DataTable con los datos que queremos mostrar (en este caso y tal como tenemos definida la vista de MySQL, queremos mostrar la factura número 4), establecer que el origen de datos del informe será este DataTable y finalmente solicitarle al CrystalReportViewer que nos muestre este informe.

Ejecutamos nuevamente la aplicación y obtenemos la factura que queríamos:

Por supuesto en una factura auténtica faltarían datos fiscales, logotipos, impuestos, condiciones de pago y demás, pero lo que aquí pretendía era únicamente mostrar cómo llevar a cabo el informe en sí mismo.

Con esto queda visto cómo simplemente utilizando un archivo XML podemos crear un informe en VisualBasic.NET. Por supuesto habría que mejorar muchas cosas, por ejemplo optimizar cómo se realiza la conexión con la base de datos (particularmente tengo un clase para llevar a cabo esa serie de cuestiones), también evitar poner la condición WHERE directamente en la vista de MySQL y sí por ejemplo cuando recuperamos el DataTable... en fin, unas cuantas cosas. Pero lo que buscaba con este ejemplo era hacer algo muy minimalista para que quedara claro el funcionamiento.

Actualización.

A raíz de uno de los comentarios he añadido una pequeña segunda parte a este post, en la que se explica cómo pasar parámetros desde el formulario hasta el informe.

Tags: , , , , , , , , , ,

39 Responses to “Informe en .NET con Crystal Reports y base de datos MySQL.”

  1. Cristhian se atrevió a comentar:

    Hola amigo Albert Mata, realmente muchas gracias por esta clase, me ha servido bastante!!! porque era lo que andaba buscando, y a pesar de no ser tan complicado me anadaba haciendo un mundo.
    Cuando la realidad era algo sencillo (pero hay q saberlo) y nada reiterarte las gracias

    Saludos

  2. Albert Mata se atrevió a comentar:

    Gracias a ti por el comentario, Cristhian. Realmente no es complicado, pero hasta que lo encuentras te puedes liar un poco, sí. Vamos, a mí me pasó. ¡Un saludo!

  3. Iván se atrevió a comentar:

    También quería darte las gracias por este tutorial, aun no me ah surgido la necesidad de usar Crystal Reports pero seguro que pronto lo usare así que esto me vendrá muy bien. Muchas gracias.

  4. Gabriel se atrevió a comentar:

    Gracias por el tutorial. Tengo un problemita quiero mostrar cada una de las filas del DataTable en páginas distintas en el reporte del crystal. Utilizando RD.SetDataSource(DT) y luego Me.crvBill.ReportSource = RD solo muestra la ultima fila del DT, cual sería la posible solución.
    saludos.

  5. Albert Mata se atrevió a comentar:

    Si te soy sincero no termino de entender lo que quieres hacer: 1) que cada artículo de la factura aparezca en una página distinta (un artículo en cada página) o 2) que todos los artículos aparezcan en todas las páginas repetidamente. ¿Has probado a jugar con las distintas secciones del informe en Crystal Reports? Igual por ahí sacas algo. Si no, no dudes en volver a contactar conmigo y veremos qué podemos hacer.

  6. Gabriel se atrevió a comentar:

    Albert lo que estoy haciendo es sencillo, en el datatable, en sus filas tengo distintas facturas por eso necesito mostrarlas en paginas distintas. Desde ya muchas gracias por tu tiempo.
    Gabriel, desde Argentina, Mendoza.

  7. Gabriel se atrevió a comentar:

    Albert pude solucionar el problema, hay que crear grupos en el reporte de crystal report y que estos los muestre en paginas diferentes, desde ya muchas por tu tutorial.

  8. maka7 se atrevió a comentar:

    Muchas gracias por el tutorial, me ha sido de gran utilidad, me gustaria preguntarte si se puede quitar o cambiar lo de "Informe Principal" debajo de la barra de navegacion, ya que en mi programa voy a generar varios informes y no me parece adecuado que salga siempre "Informe Principal". Gracias por la ayuda.

  9. Albert Mata se atrevió a comentar:

    Si se puede, no sé hacerlo. He mirado las propiedades del objeto CrystalReportViewer si permite quitar ese botón y no lo he encontrado. Ahora bien... prepárate para leer la solución más poco elegante que habrás leído en tu vida... si añades al formulario una simple etiqueta (Label), le pones el AutoSize a False, le quitas el texto, la dimensionas como quieras y la ubicas donde corresponde... el efecto óptico final es idéntico que si ese botón (que ahora queda debajo de la etiqueta) no existiera.

  10. maka7 se atrevió a comentar:

    Gracias Albert, no es muy elegante pero es practico. Me gustaría preguntarte otra cosilla q me tiene un poco liada. Necesito pasar un parametro desde un textbox al reporte y cuanto mas leo en foros mas me lio... Este es mi codigo:

    Imports CrystalDecisions.CrystalReports.Engine

    Public Class Form22

    '----------------------------------------------------------------
    ' As a first step, creates XML file.
    '----------------------------------------------------------------
    Private Sub Form22_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    'Creating XML file.
    Dim RC1 As New Class1("documento")
    'RC1.CreateXMLFile("C:\")

    'Creating report.
    Dim RD As ReportDocument = New ReportDocument()
    RD.Load("C:\Informe1.rpt")

    'Setting data source for report.
    Dim DT1 As DataTable = RC1.GetDataTable()

    RD.SetDataSource(DT1)

    'Setting data source for possible subreports.
    For Each SR As ReportDocument In RD.Subreports
    If SR.Database.Tables.Count > 0 Then
    SR.SetDataSource(DT1)
    End If
    Next

    'Setting recently created report must be shown in viewer.
    Me.CrystalReportViewer1.ReportSource = RD
    End Sub
    End Class

    Muchas gracias por su tiempo.

  11. Albert Mata se atrevió a comentar:

    ¡Gracias por llamarme chapucero! ;-)

    Para pasar un parámetro desde un Textbox al reporte puedes probar si te sirve algo así:

    1) En el Explorador de campos del informe, te sitúas en Campos de parámetro, haces click derecho, seleccionas Nuevo, le informas un nombre (p.ej. Test) y le das a aceptar.
    2) Ahora dentro de Campos de parámetro tendrás el parámetro Test disponible para arrastrarlo hasta el punto del reporte que desees. Hazlo.
    3) Por último al final de todo del procedimiento (después de establecer el ReportSource = RD), añades las siguientes líneas:
    'Setting report's parameter.
    RD.SetParameterValue("Test", "Sthg coming from Textbox")

    Yo le he mandado un literal, pero obvio le puedes mandar lo que quieras (cuando creaste el campo de parámetro habrás observado que le podías indicar de qué tipo de datos se trataría).

  12. maka7 se atrevió a comentar:

    umm, fallo mio q no me e explicado bien, kiero pasar el parametro desde el textbox de mi form, lo que seria algo asi supongo
    RD.SetParameterValue(”Test”, textbox1.text) por lo que no quiero que salga la ventana para pedirme el valor.
    Pero la variables test, se la quiero asociar a uno de los campos de mi base de datos. Explico, por ejemplo si le paso a test el valor 1, pues generar el reporte factura cuyo numero sea 1, como asocio el campo del textbox con el de la base de datos??

  13. Albert Mata se atrevió a comentar:

    Qué tal maka7. Te he enviado un correo con una posible solución, ya que al ser algo más compleja me parece buena idea crear una segunda parte de este post incorporando estas opciones. Pero como lo haré con algo más de calma mañana, te he avanzado el contenido de dicho post.

  14. Luis Lopez se atrevió a comentar:

    Albert, muchas gracias es de gran utilidad este tutorial

  15. Ivan Coronel se atrevió a comentar:

    Muchisimas gracias, me sirvio mucho no sabes las vueltas que di para poder conectar el bendito crystal con mysql, al hacerlo con odbc no tenia problemas pero al cambiarme y usar el conector para .net me hice lios. Muchas gracias nuevamente.

  16. Jose se atrevió a comentar:

    Te hago una consulta de casoalidad, sabes como mostrar en crystal report imagenes guardadas en una base de datos slq 2000 en un campo imagen.
    Por que cuando hago el reporte en el cuadro de la imagen me queda en blanco. Si me podes dar una idea te lo agradeceria.

    Saludos, y muy bueno el post

  17. Albert Mata se atrevió a comentar:

    Gracias. Lamentablemente no puedo ayudarte porque no he trabajado nunca con SQL2000 y no sé cómo puede funcionar eso que comentas. Si lo descubres agradeceré que vuelvas para postearlo... ;-)

  18. Makio se atrevió a comentar:

    Hola que tal buen articulo me gusto pero una pregunta me parece o en uno de los metodos estas volviendo a crear el archivo xml en esta parte ::

    Imports CrystalDecisions.CrystalReports.Engine

    Public Class frmMain

    '----------------------------------------------------------------
    ' Creates XML file (just once) and creates and loads a report.
    '----------------------------------------------------------------
    Private Sub frmMain_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
    'Creating XML file.
    Dim RC As New clsReportCreator("zbl_bill2print")
    'RC.CreateXMLFile("C:\")

    -- hasta aqui al llamar a esa funcion de esa clase crea el archivo xml son los campos predefinidos y tamb añade sus datos ? .. lo digo por esto DT.WriteXmlSchema(FilePath & Me.TableOrView & ".xml") o es que solo es para crear el xml con solamente sus campos sin llenar sus datos o registros ?

    'Creating report.
    Dim RD As ReportDocument = New rptBill()

    'Setting data source for report.
    Dim DT As DataTable = RC.GetDataTable()

    --y aqui lo llenas de nuevoo eso no entiendo bien me podrias explicar porque pareciera o es que aqui si solo llena los datos de la tabla vista?
    RD.SetDataSource(DT)

    'Setting data source for possible subreports.
    For Each SR As ReportDocument In RD.Subreports
    If SR.Database.Tables.Count > 0 Then
    SR.SetDataSource(DT)
    End If
    Next

    'Setting recently created report must be shown in viewer.
    Me.crvBill.ReportSource = RD
    End Sub

    End Class

    porfa agradeceria me escribas ami email porfa y me saque es de duda de verdas que lo nesesito y muchas gracias de antemano

  19. Albert Mata se atrevió a comentar:

    El archivo XML sólo se crea una vez con la llamada a RC.CreateXMLFile(”C:\”) y lo crea vacío de datos (únicamente estructura). Sirve para crear a su vez la estructura del informe. Hasta aquí nada de datos.

    Más adelante y de manera totalmente independiente al paso anterior, se crea un DataTable lleno de datos (obvio tendrán que tener la misma estructura que el archivo XML o al menos muy parecida) y se le envía al informe para que aprovechando la estructura que éste ya tenía, los muestre. Esto se hace con la llamada RD.SetDataSource(DT).

    Si te fijas bien, la llamada RC.CreateXMLFile(”C:\”) sólo aparece una vez sin comentar y el resto de veces comentada para que no se aplique.

    De todos modos todo esto ya está explicado en el artículo... ;-)

    "Nótese que ahora ya he comentado la línea en que creamos el archivo XML, puesto que sólo necesitamos crearlo una única vez para luego poder generar el origen de datos, pero a partir de aquí no necesitaremos andar creándolo cada vez."

  20. XBoy se atrevió a comentar:

    Hola Albert, ante todo felicitarte, ya que todos estos codigos vienen muy bien para la gente que estamos aprendiendo. Y es que tengo un problema y es que me da una un error SqlException en este punto DA.Fill(DS, Me.TableOrView), e cambiado esto
    Imports MySql.Data.MySqlClient por Imports System.Data.SqlClient,
    ya que la otra de mysql no me la cogia, espero que no influyera.
    bueno pues nada sigue asi, y grascias de antemano.

  21. Albert Mata se atrevió a comentar:

    Si no estás trabajando con MySQL, ni idea, no he probado otras bases de datos así que no puedo orientarte.

    Si estás con MySQL:

    1. Recuerda que previamente tendrás que haberte instalado el conector de MySQL para .NET (http://dev.mysql.com/downloads/connector/net/5.2.html).

    2. En el proyecto, previamente tendrás que hacer Proyecto ---> Agregar referencia ---> .NET ---> MySQL.Data ---> Aceptar.

    A partir de aquí, el Imports MySql.Data.MySqlClient tiene que funcionar.

  22. Jean Paul Tolhuijsen se atrevió a comentar:

    Aqui va mi codigo pasando parametros de un control a la consulta de mysql. Los unicos cambios es que la clase la hago en el mismo form para pasarle los parametros "divididos". Notese que clasifico los reports mediante fechas, y como MySQL trabaja con cierto formato le di formato en el mismo codigo, imponiendo los "-".
    Espero les sirva

    Imports MySql.Data.MySqlClient
    Imports CrystalDecisions.CrystalReports.Engine
    Public Class frmMain2
    Sub muestrareporte()
    Dim cad As String = Me.DateTimePicker4.Text()
    Dim RC As New conexion_report2("notificacion_2,predio where notificacion_2.fecha = '" & cad & "' and notificacion_2.cod_fundo = predio.cod_predio")
    'RC.CreateXMLFile("C:\")
    Dim RD As ReportDocument = New notificacion_inicial()
    Dim DT As DataTable = RC.GetDataTable()
    RD.SetDataSource(DT)

    For Each SR As ReportDocument In RD.Subreports
    If SR.Database.Tables.Count > 0 Then
    SR.SetDataSource(DT)
    End If
    Next
    Me.CrystalReportViewer1.ReportSource = RD
    End Sub
    Private Sub ToolStripButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton1.Click
    muestrareporte()
    End Sub
    Private Sub frmMain2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    DateTimePicker4.Format = DateTimePickerFormat.Custom
    DateTimePicker4.CustomFormat = "yyyy-MM-dd"
    DateTimePicker4.MinDate = New DateTime(1985, 6, 20)
    DateTimePicker4.MaxDate = DateTime.Today
    End Sub
    End Class

    Public Class conexion_report2
    Private TableOrView As String
    Public Sub New(ByVal TableOrView As String)
    Me.TableOrView = TableOrView
    End Sub
    Public Function GetDataTable() As DataTable
    Dim DA As MySqlDataAdapter
    Dim DS As New DataSet
    Dim DT As DataTable
    Dim ConnectionString As String
    Dim SQL As String
    Dim query As String
    'String de conexion.
    query = "select * from notificacion"
    ConnectionString = "Database = carranco2; " _
    & "Data Source = localhost; " _
    & "User ID = root; " _
    & "Password = 123"
    'Seteamos una consulta SQL.
    SQL = "SELECT notificacion_2.num_serie as NOTIFICACION,notificacion_2.fecha AS FECHA,notificacion_2.camino AS CAMINO,notificacion_2.cancha AS CACHA,predio.nom_predio AS FUNDO,notificacion_2.almacen AS ALMACEN,notificacion_2.gestion as GESTION ,notificacion_2.acta as ACTA,notificacion_2.secuencia as SECUENCIA,notificacion_2.rut as RUT,notificacion_2.pago as PAGO,notificacion_2.inicio_j as INICIO,notificacion_2.fin_j as FINAL,notificacion_2.n_c_madereo as CICLOS_MADEREO,notificacion_2.t_colacion as TIEMPO_COLACÎON,notificacion_2.h_horometro as HOROMETRO,notificacion_2.n_personas as N_PERSONAS,notificacion_2.cod_equipo_madereo AS EQUIPO,notificacion_2.labor as LABOR ,notificacion_2.total_aserrables as TOTAL_ASERRABLES_M3,notificacion_2.total_pulpables as TOTAL_PULPABLES_M3 FROM " & Me.TableOrView
    'Sacando informacion y llenando los DataSet y DataTable.
    DA = New MySqlDataAdapter(SQL, ConnectionString)
    DA.Fill(DS, Me.TableOrView)
    DT = DS.Tables(Me.TableOrView)
    'devuelvo valores desde el DT.
    Return DT
    End Function
    '----------------------------------------------------------------
    ' Creo el archivo XML en el disco
    '----------------------------------------------------------------
    Public Sub CreateXMLFile(ByVal FilePath As String)
    Dim DT As DataTable
    'Creacion del datatable.
    DT = Me.GetDataTable()
    'escribiendo el xml en el path deseado.
    DT.WriteXmlSchema(FilePath & Me.TableOrView & ".xml")
    End Sub
    End Class

  23. Brian Pando se atrevió a comentar:

    Hermanoooo!!,,, me has ahorrado muchas neuronas, es decir, tu información esta excelente, esto se busca mucho, pero poco se encuentra, yo lo he trabajado con MS SQL, con unas ciertas modificaciones, pero todo ok, ahora si no es mucho pedir, ¿como se hace esto de las subreports?, manualmente claro, no de forma visual.

  24. Arnau se atrevió a comentar:

    Hola Albert,

    primero..gracias! Tu artículo me ahorró mucho tiempo cuando creé reports a través de XML, pero en mi caso con SQL Server.

    Pero me ha surgido un problema que no se como resolver: Los reports tienen una ruta absoluta para encontrar los XML, pero claro, al hacer la instalación esta ruta no será la misma!

    Sabes si hay alguna forma de solucionarlo? Sea pasandole por codigo la ruta relativa o dentro del report mismo? Lo he estado intentando, pero no lo reconoce correctamente.

    Muchas gracias!!

  25. sak_nyappy se atrevió a comentar:

    gracias por tu articulo me sirvio mucho, pero tengo un problema en Me.crvBill.ReportSource = RD de donde sale el crvBill por q los nombre diferentes y no se q poner ahi

    y gracias de nuevo por tu articulo!!

  26. sak_nyappy se atrevió a comentar:

    tengo otra duda, si en una tabla tengo un campo con la direccion de una imagen, ¿se puede hacer q en el reporte se muestre la imagen??
    Si me puedes sacar de la duda te lo agradeceria mucho :)

  27. Albert Mata se atrevió a comentar:

    "Para ello en el formulario frmMain añadiremos un objeto de tipo CrystalReportViewer al que llamaremos por ejemplo crvBill."

    Respecto a lo segundo, en tanto que no lo he necesitado nunca la verdad es que lo ignoro. Todo es cuestión de añadir una imagen e indagar en sus propiedades si admite que se la pases como parámetro (ver post sobre cómo pasar parámetros reseñado en la actualización a este post).

  28. Pau se atrevió a comentar:

    tengo la misma problematica que Arnau que la instalacion puede hacerse en distintas rutas. En mi caso, los usuarios trababan en Red y pueden ser 3 5 o 200, si todos trabajan sobre el mimos XML, es totalmente logico que antes o despues se pisen las facturas uno al otro, asi que, estoy buscando la manera de crear un XML, factura + numero fra + usuario.XML
    Logicamente el Reporte tiene que ir a buscar el XML, factura + numero fra + usuario.XML

    Le estoy dando muchas vueltas y esto tiene que poder hacerlo el Crystal..
    Un Saludo
    de Rubio, Pau

  29. Albert Mata se atrevió a comentar:

    No ens estem entenent... ;-)

    Da igual dónde pongáis el archivo XML. Este archivo sólo contiene la estructura de datos, pero no tiene datos en sí mismo. Se utiliza únicamente en tiempo de diseño del informe para decirle este campo aquí, este allá, pero después si queréis podéis incluso borrarlo. Una vez está diseñado el informe el archivo XML ya no se utiliza para nada en ningún momento.

    Los datos al informe le llegan a través del DataTable correspondiente. Evidentemente ese DataTable deberá tener la misma estructura (o muy parecida) que tiene el archivo XML (no en vano ambos se han creado a partir de la misma tabla de la base de datos).

  30. Isidre se atrevió a comentar:

    NO entenc el funcionament del dataset ... acostumo a treballar
    amb ADODB ... recupero les dades que em fan falta en els corresponents recordsets ... i de moment, el que no aconsegueixo es passar aquets registres al report (previament definit des de xml)

  31. Arnau se atrevió a comentar:

    Aviam si no en entrendran els altres parlant així! :P

    Pau, encontré la solución en documentación en ingés: http://aspalliance.com/1097

    Espero que te sirva!!!

  32. Pau se atrevió a comentar:

    Dons xerrem en Cast!.. ;)

    Bien yo encontre la siguiente manera y me va genial. Os paso 1 ejemplo.
    Lo he complicado con parametros para la cabecera.
    No se si se explica bien aqui o no, xo si teneis dudas de como hacerlo.. me dais un toke.
    ________________________________________________

    Dim fecha, nombre As String
    ConnSQLtpv(r, c, "SELECT fecha, nombre FROM MyTabla WHERE fecha = '" & fecHa & "'")
    If Not r.EOF Then
    fecha = r.Fields("fecha").Value
    nombre = r.Fields("nombre").Value
    End If

    Dim parmfields As CrystalDecisions.Shared.ParameterFields = fcierrecaja.CrystalReportViewer1.ParameterFieldInfo

    Dim parmfield1 As New CrystalDecisions.Shared.ParameterField()
    Dim parmValue1 As New CrystalDecisions.Shared.ParameterDiscreteValue()

    Dim parmfield2 As New CrystalDecisions.Shared.ParameterField()
    Dim parmValue2 As New CrystalDecisions.Shared.ParameterDiscreteValue()
    Dim parmValues As New CrystalDecisions.Shared.ParameterValues()
    parm1 = fecha
    parm2 = nombre

    parmValue1.Value = parm1
    parmfield1.Name = "Fecha"
    parmValue2.Value = parm2
    parmfield2.Name = "Nombre"

    Dim DS As DataSet
    Dim SQL As String = "select facturas, cantidad, doc_cobro from facturas where nombre='" & nombre & "'"

    ReportTGV(SQL, "registro", DS)

    Dim report As ReportDocument
    report = New ReportDocument

    report.Load(ruta & "\informe.rpt")
    report.SetDataSource(DS)

    fcierrecaja.CrystalReportViewer1.ReportSource = report

    report.ParameterFields(parmfield1.Name).CurrentValues.AddValue(parmValue1.Value)
    (parmfield2.Name).CurrentValues.AddValue(parmValue2.Value)

    fcierrecaja.Show()
    ______________________________________________

  33. Albert Mata se atrevió a comentar:

    @Isidre, potser hauries de plantejar-te fer servir DataSet enlloc dels RecordSet de tota la vida (vaja, d'abans). Un DataSet d'alguna manera no és més que un conjunt de DataTable, que vindrien a ser els equivalents al RecordSet. Vaja, que no hi ha massa canvi i potser hi sortiries guanyant.

  34. david se atrevió a comentar:

    baste buena tu informacion albert mata, me sirvio de mucho gracias, es pero q subas tambien en codigo para los que programan en c#

  35. Juan Martin se atrevió a comentar:

    Hola gente, a ver si alguien me puede ayudar, el problema que estoy teniendo es que necesito que el campo "Total" de mi factura tenga una posición fija en el pie del informe pero no puedo lograrlo ya que me varía el margen superior de acuerdo a la cantidad de items que tengo en el detalle.

    Alguien sabe como resolver esto?

    MUCHAS GRACIAS!!!

  36. Albert Mata se atrevió a comentar:

    @david, sin problemas... tú pagas y yo codifico en C#... :-p

    @Juan Martin, ¿y por qué no pones el campo en la sección pie del informe?

  37. Juan Martin se atrevió a comentar:

    Hola Albert, te cuento que el campo lo tengo en la sección 'Pie del Informe' pero debe ser o que lo tengo mal configurado o algo estoy haciendo mal, ya que como te decia cuando crece la sección 'Detalle' me va tirando todo para abajo.

    Gracias por la respuesta!

  38. Albert Mata se atrevió a comentar:

    Pues ahora no tengo el portátil delante, lo siento, pero el viernes si saco un momento te miro qué puede ser, que me ha intrigado el tema. Dame un toque si ves que no digo nada, please.

  39. sergio se atrevió a comentar:

    hola yo tengo un problema parecido al de juan marin, necesito que el total de la factura este en una posicion fija, pero si lo pongo en el pie del informe, sale muy abajo y yo necesito que salga unos centimetros mas arriba porque las hojas en donde se va a imprimir ya tienen un formato.
    Gracias.

Leave a Reply