ReportViewer y fuentes de datos dinámicas

Durante las últimas semanas he estado enfrascado en labores de mantenimiento de aplicaciones un poco «viejitas» y entre las tareas está la incorporación de algunos requerimientos hechos por los usuarios de modificaciones a los informes, creación de nuevos, etc.  Por los días en que fueron programadas originalmente, solía usar componentes de terceros para la creación de informes, los cuales resultaron muy eficaces y aún hoy están sirviendo informes felizmente.  Sin embargo no siempre se obtiene ciento por ciento de compatibilidad con las versiones nuevas de .NET; así las cosas, decidí echar una ojeada a ReportViewer que viene incluído con Visual Studio 2008.  A primera vista me pareció un poco frívolo, con pocas posibilidades de personalización, gracias a la manía de Microsoft de ponernos las cosas estúpidamente simples; con el asistente y unos cuantos clicks, es posible en menos de un minuto obtener una forma de Windows o una página web que muestre un informe completamente funcional, eso sí, monolíticamente ligado a una tabla específica o expresión SQL.  A continuación intentaré mostrar cómo utilizar ReportViewer para mostrar informes a partir de fuentes de datos creadas dinámicamente en tiempo de ejecución.

Acerca de ReportViewer

A modo de preámbulo, ReportViewer es un control gratis que permite incluir informes en las aplicaciones web y desktop (http://www.gotreportviewer.com/).  Posee dos modos de operación:  local y remoto.  Cuando trabaja en modo remoto, simplemente muestra un informe creado por un Servidor de Informes de SQL Server.  En modo local, todo el procesamiento, filtrado u ordenamiento ocurren a nivel de cliente.  En este post se asume que estamos trabajando en modo local (propiedad ProcessingMode=local). 

Conceptualmente, para completar un informe con ReportViewer son necesarios dos componentes:

  • La definición del informe, que en este caso es un documento en formato RDLC (Report Definition Language for Client).
  • La fuente de datos, un DataSet.

Uno de los aspectos positivos de ReportViewer es la independencia entre estos componentes; la definición del informe no está ligada a ningún formato específico de base de datos, ni a ninguna base o tabla específica.  De ahí la posibilidad de construir una definición sin conocer el origen exacto de los datos; solo es necesario especificar de forma abstracta los nombres de campos que debe incluir una tabla que sirva de fuente de datos al informe y sus tipos de datos.

Usualmente construyo las aplicaciones empleando las tradicionales capas lógicas (tiers) de acceso a datos, negocios e interfaz; uno de los módulos se especializa en la construcción de los DataSets que sirven de base a los informes.  Este método me resultó siempre muy útil con los componentes de terceros, pues me permitía cambiar de uno a otro sin modificaciones (o mínimas) en el resto de las capas.  Afortunadamente, a ReportViewer le he podido también «enchufar» los DataSets generados por estos módulos previamente construídos.  Solamente he tenido que crear nuevamente las definiciones de los informes en el nuevo lenguaje RDL, aunque esto es fácil con las herramientas visuales de Visual Studio.

Obtención del Conjunto de Datos

Para entrar en materia, voy a emplear un ejemplo muy simple: se desea mostrar en una página .aspx un informe que liste los atletas finalistas en unos Juegos Olímpicos.  En el sistema real se le permite al usuario seleccionar la edición de los Juegos, el deporte y la modalidad, de ahí que la fuente de datos tenga que ser dinámica.  Definiré una función CalcularDataSet() que retorna los finalistas de 100 metros planos en atletismo durante los Primeros Juegos Olímpicos celebrados en Atenas, Grecia en 1896.  Esta función es un patrón que simplifica el verdadero cómputo del DataSet, que puede ser todo lo complicado que se desee y generalmente residiría en la capa de acceso a datos o en la capa de negocios.  Por tanto, incluyo el código por completitud, pero no es importante para comprender el mecanismo que nos ocupa.  El aspecto relevante es que la función devuelve un DataSet que contiene el DataTable que servirá de fuente de datos al informe.

public DataSet CalcularDataSet()
{
    string sql = @"
            SELECT  posiciones.lugar,
                    atletas.nombre,
                    atletas.apellido1,
                    delegaciones.nombre AS Pais,
                    posiciones.resultado,
                    eventos.nombre AS Evento,
                    eventos.sigDeporte
            FROM atletas INNER JOIN integrantesGrupos ON atletas.idAtleta = integrantesGrupos.idAtleta
                    INNER JOIN posiciones
                    INNER JOIN Competencias ON posiciones.idCompetencia = Competencias.IdCompetencia
                    INNER JOIN eventos ON posiciones.idEvento = eventos.idEvento
                    INNER JOIN Categorias ON Competencias.Categoria = Categorias.IdCategoria ON integrantesGrupos.idResultado = posiciones.idPosicion
                    INNER JOIN delegaciones ON posiciones.idDelegacion = delegaciones.idDelegacion
            WHERE categorias.idclase=1
                    AND competencias.categoria=2
                    AND posiciones.idCompetencia=286
                    AND eventos.sigDeporte='ATL'
                    AND posiciones.idEvento=14
                    AND posiciones.idFase=3
                    AND posiciones.sexo='M' ";
    string connstr = "Data Source=localhost;Initial Catalog=historia;Integrated Security=True";

    SqlConnection conn = new SqlConnection(connstr);
    SqlCommand cmd = new SqlCommand(sql, conn);

    SqlDataAdapter da = new SqlDataAdapter();
    da.SelectCommand = cmd;

    conn.Open();

    DataSet ds = new DataSet();
    da.Fill(ds, "Finalistas");

    conn.Close();
    return ds;

}

 Creación de la Definición del Informe (documento RDLC)

 El documento RDLC es simplemente un documento XML que cumple con el esquema del lenguaje RDLC.  Por tanto, en caso extremo, es posible crearlo con cualquier editor de textos.  En la práctica, por supuesto, resulta más conveniente emplear las herramientas visuales que proporciona Visual Studio.   Para ello añadimos al proyecto un nuevo item de tipo Report y lo denominaremos Finalistas.rdlc.   Ello muestra el diseñador de informes con un informe vacío.  Aquí arrastramos desde la barra de herramientas un nuevo Table, añadimos las columnas necesarias y les colocamos sus respectivos títulos en la fila de encabezados (Header).

Si compilamos el proyecto, Visual Studio «protestará» debido a que no se ha definido un DataSource en el informe.  Debemos añadir entonces un DataSet nuevo al proyecto.  En este momento contamos con al menos dos opciones:

  1. Estilo bottom-up: construir un DataSet a partir de la base de datos real, suministrando una consulta en SQL a través de un Table Adapter, un procedimiento almacenado, etc.
  2. Estilo top-down: construir un DataSet «ficticio» con una tabla que solo va a contener los nombres de los campos que vamos a utilizar en el informe.  Este es el enfoque que se sigue aquí.

Ambos métodos son igualmente válidos.  El verdadero objetivo de este paso es crear una fuente de datos que sea «comprensible» para el diseñador de informes de Visual Studio.  De regreso al informe, aparecerá en la ventana «Website Data Sources» el nuevo DataSet creado que denominamos DataSetFinalistas.   En el diseñador de DataSets obtuve una tabla que denominé TableFinalistas que luce así:

tablefinalistas

Para completar la definición del informe solo debemos arrastrar los campos correspondientes desde la ventana «Website Data Sources» hacia la fila de detalles (Detail) de la tabla que insertamos anteriormente y añadir las opciones de formato deseadas.

Luego de guardar el documento, para comprender mejor qué hemos hecho, conviene echar una ojeada al documento RDLC generado.  Por cualquiera de los dos métodos señalados, se creó una sección que contiene la definición del DataSet.  Por cierto, es curioso notar cierta ambiguedad en el término DataSet en este contexto: para RDLC el DataSet es más bien una tabla o la definición de sus campos, contrario a .NET dónde DataSet es una estructura de datos que contiene tablas (DataTable); nada alarmante pero conviene estar claros de esta sutileza para evitar confusiones.  La sección de DataSets del RDLC para nuestro ejemplo, queda de la siguiente forma:

  <DataSets>
    <DataSet Name="DataSetFinalistas_TableFinalistas">
      <Fields>
        <Field Name="lugar">
          <DataField>lugar</DataField>
          <rd:TypeName>System.String</rd:TypeName>
        </Field>
        <Field Name="nombre">
          <DataField>nombre</DataField>
          <rd:TypeName>System.String</rd:TypeName>
        </Field>
        <Field Name="apellido1">
          <DataField>apellido1</DataField>
          <rd:TypeName>System.String</rd:TypeName>
        </Field>
        <Field Name="pais">
          <DataField>pais</DataField>
          <rd:TypeName>System.String</rd:TypeName>
        </Field>
        <Field Name="resultado">
          <DataField>resultado</DataField>
          <rd:TypeName>System.String</rd:TypeName>
        </Field>
        <Field Name="evento">
          <DataField>evento</DataField>
          <rd:TypeName>System.String</rd:TypeName>
        </Field>
        <Field Name="sigDeporte">
          <DataField>sigDeporte</DataField>
          <rd:TypeName>System.String</rd:TypeName>
        </Field>
      </Fields>
      <Query>
        <DataSourceName>DummyDataSource</DataSourceName>
        <CommandText />
        <rd:UseGenericDesigner>true</rd:UseGenericDesigner>
      </Query>
      <rd:DataSetInfo>
        <rd:DataSetName>DataSetFinalistas</rd:DataSetName>
        <rd:TableName>TableFinalistas</rd:TableName>
      </rd:DataSetInfo>
    </DataSet>
  </DataSets>

Esto, usando el segundo método.  La única diferencia en cuanto a generación entre ambos métodos es que con el primero, se incluye más información en la definición, por ejemplo el comando que se utiliza para generar los datos (CommandText), la cadena de conexión (ConnectString), y otros que en un final son irrelevantes pues todo esto lo vamos a generar en ejecución.  Nótese en la sección <Query> la «fuente de datos tonta» (DummyDataSource).  Todas estas secciones, Query, CommandText, DataSourceName, son obligatorias y es necesario incluirlas aunque estén vacías si no queremos escuchar las quejas del compilador.

En fin, la elección de uno u otro método es una cuestión de gusto y comodidad, si estamos seguros de los campos que vamos a utilizar, entonces el (2) es más simple; si antes queremos jugar un poco con los datos o crear aquí mismo la consulta entonces (1) es más cómodo.  Como quiera, lo único importante para realizar el diseño del informe y crear el correspondiente RDLC, es la definición de los nombres de campos que se van a usar.

Informe = Definición en RDLC + Datos 

Ya tenemos una función que genera DataSets (de .NET), o en una aplicación real, todo un componente dentro de la capa de datos; y tenemos un RDLC que contiene la definición del informe.  Ahora solo resta buscar la forma de aglutinarlos a ambos.

Muy sencillo, supongamos que nuestro proyecto es una aplicación web en el cual tenemos una página llamada finalistas.aspx en la cual depositamos un ReportViewer llamado rv.  Además tenemos un botón «Mostrar finalistas» que carga el informe en el ReportViewer.  El código es el siguiente:

protected void MostrarInforme()
{
    ReportDataSource rds = new ReportDataSource();
    rds.Name = "DataSetFinalistas_TableFinalistas";
    rds.Value = CalcularDataSet().Tables[0];

    rv.LocalReport.DataSources.Clear();
    rv.LocalReport.DataSources.Add(rds);
    rv.LocalReport.ReportPath = "Finalistas.rdlc";
    rv.LocalReport.Refresh();
}

ReportDataSource es la estructura que permite asociar el DataSet referenciado en la definición del informe con un conjunto de datos (DataTable en este caso)  generado dinámicamente en tiempo de ejecución.  El punto importante aquí es que debe coincidir el Name del ReportDataSource con el Name del DataSet en el RDLC (en este caso DataSetFinalistas_TableFinalistas).

informefinalistas

Un par de temas abiertos

Para terminar me agradaría compartir un par de temas abiertos con los que he tropezado en el trabajo con ReportViewer.  El primero es específico a la versión para web.  Si fijamos las dimensiones del control en tiempo de diseño, en ejecución se mostrarán barras de desplazamiento automáticamente en caso que el tamaño real sea mayor que el predeterminado.  Fijando la propiedad SizeToReportContent a True, es posible indicarle a ReportViewer que ajuste el tamaño del control en tiempo de ejecución al tamaño real del informe.  Sin embargo, para que esto funcione, es necesario fijar la propiedad AsyncRendering a False, de lo contrario ni se entera.  Pero con esta configuración (AsyncRendering=False y SizeToReportContent=True) no me funciona el páginado, al hacer click para mostrar la siguiente página, sigue mostrando la primera.

He estado experimentando algunas de las variantes en este post para resolver el problema y creo que la solución está por esa vía jugando un poco con los javascripts, aunque honestamente, me ha faltado el tiempo para probarlo con más profundidad.  Si alguien lo ha hecho, por favor, me deja un comentario por acá.

El segundo se refiere a la generación dinámica del RDLC, o sea, de la definición del informe.  Esto abre una amplia gama de posibilidades, la definición en RDLC es finalmente un XML que podemos construir en tiempo de ejecución.  He incluído en mi lista de tareas utilizar esta variante para construir informes basados en consultas cruzadas, en las cuales es imposible predecir en tiempo de diseño la cantidad de campos.  Recomiendo descargar la aplicación de ejemplo Dynamic Matrixeste post en el cual se construye el RDLC aplicando una transformación XSLT al esquema del DataSet que contiene el resultado de la consulta

En general, ReportViewer resulta muy útil y fácil de usar y aunque no es nueva la idea de separa definición de datos, me parece muy acertada la idea de emplear este enfoque.  Es posible descargar las especificaciones del lenguaje RDL del 2008 desde el sitio de Microsoft de SQL 2008.

72 Responses to ReportViewer y fuentes de datos dinámicas

  1. Juan Noriega says:

    Como llamas al reporte rdlc por medio de parametros?

  2. Robert says:

    Gran aporte man….. realmente espectacular. Es muy bueno no guiarnos solamente por los wizard y hacer algo mas inteligente… Palmas para ti

  3. Arturo says:

    Realmente usted es el primer ser en este planeta que en realidad muestra algo util, estaba varado, llevo mas de un mes buscando alguien que me luces sobre este tema.

    gracias

  4. Arturo says:

    Algo Adicional:

    el metodo seria el mismo para visual basic??????

  5. johnbarquin says:

    Hola Arturo, me alegra le haya sido útil esta información. En efecto, es posible implementar el método también en VB pues como cualquier lenguaje sobre .NET, soporta ADO.NET y ReportViewer.

    Saludos

    • Me podría ayudar con algo?
      Ya implementé lo que me faltaba pero al momento de presionar el botón «generar reporte» me sigue mandando el mismo mensaje «No se ha proporcionado ninguna instancia de origen de datos para el origen de datos ‘DataSet1’.»
      Espero que pueda contestar.
      Gracias

      • christian says:

        Hola, fijate que el nombre que estas enviando desde el código se tiene que llamar de la misma manera que el dataset que utilizas cuando diseñas el rdcl

        si cuando diseñaste el rdcl le pusiste DataSet1, cuando le indicars el datasource debes llamarlo de la misma manera….

        var reporteDataSource = new ReportDataSource(«DataSet1», (DataTable)dataTable);

    • Me podría ayudar con algo?
      Ya implementé lo que me faltaba pero al momento de presionar el botón «generar reporte» me sigue mandando el mismo mensaje «No se ha proporcionado ninguna instancia de origen de datos para el origen de datos ‘DataSet1’.»
      Sólo que yo estoy trabajando con Visual Studio 2012 c#
      Espero que pueda contestar.
      Gracias

  6. jaime tovar says:

    Buenos comentarios yo hes estado desarrolonado 2008 pero tengo para problemillas la de la orientacion del papel y la de impresión del lado del cliente he leido varios post y el que me funcion lo de la impresion es el siguiente:
    http://idelabar.blogspot.com/2008/10/problemas-para-imprimir-con-report.html
    mucho agradeciari si tienes solicon para el tamaño y orientacion del papel (horizontal)
    saludos y felicidades por tus comenarios realmente es algo funcional.

  7. Edson says:

    excelente documento solo una preguna hay forma de agregar una columna que genere un numero consecutivo a un reporte rdlc, como en reporte de crystal que es numero de registro?, Gracias

  8. Fabian says:

    Excelente, claro y conciso, muchas gracias!!!

  9. Javier says:

    Tengo una duda, ojala puedan ayudarme, quisiera saber la manera de combinar la fuente de una caja de texto ej. lettra normal y negrita para no tener que concatenar varios cuadros de texto en un reporte hecho con reportviewer, solo se que podemos usar el fontweight pero no se como usarlo enuna expresion, ojala puedan ayudarme

  10. Juan delgado "bakiet" says:

    hola muchas gracias por esta informacion es muy buena para trabajar con reportviewer , tengo solo un problema , hice cada paso pero el reporte no muestra la data , y se que el dataset se esta llenando que puede ser , me asegure que el nombre del datasety del rdlc fuera el mismo que el del calculardataset y todo , no puedo ver que sucede , es como que no hace refrest el reportviewer , puede ser que lo estoy haciendo en windowsform ?

  11. juan says:

    HOLA johnbarquin…

    Excelente información, gracias, nada más que al generar el reporte los puntos que tengo en la base de datos me los muestra con comas

    Por ejemplo en la BD tengo 5.5 en el reporte me muestra 5,5

    Espero y me puedas ayudar, le he cambiado formato pero no he dado con la solución, saludos…..

  12. Juan says:

    La consulta es la siguiente: necesito saber si es posible personalizar una tabla dentro de un reporte.
    Me explico tengo una tabla que guarda en ella la definicion de las conductas de un individuo, para cada conducta existe una nota obtenida por el sujeto, la que necesito marcar de cierta forma (colorear, ticket) dentro de la columna que corresponda.

    CONDUCTA | NO CUMPLE | CUMPLE PARCIALMENTE |CUMPLE TODOS | SOBRESALIENTE

    siendo conducta la columna con la definicion de la conducta.

    Necesito saber si esto se puede hacer, y de poderse como se realiza, agradeceria mucho su ayuda, ya que me tiene asi cada una (xD).
    Desde ya gracias.

    pd: trabajo con c#, y cargo los datos de la tabla en un Dataset mediante codigo generado en mi documento aspx.cs

  13. JESHU says:

    Hi, John.

    Lo máximo el tutorial, busqué y busqué hasta que hallé tu tutorial . Lo máximo. Muchas gracias.

    Trabajo con Visual Studio 2008 SP1 y framework 3.5 y tengo un problema pues las barras aparecen con el mismo valo (mismo tamaño) a pesar que tienen distintos valores.

    Me podrías ayudar con eso, por favor

  14. mrc says:

    muy buen ejemplo, aun que dure casi tres dias haciendo que funcionara. porque? pues por que cuando hacia la consulta no usaba AS para que el nombre de la columna que me regresa la consulta coincidiera con la tabla que habia creado en el diseñador. un pequeño detalle que pase por alto. espero que no les pase lo mismo 😀

  15. silvi says:

    hola a todos porfa necesito urgente hacer un reporte con filtros utilizando xtrareport con punto. net si alguien tiene sabe como se lo agradecere mucho.

  16. Armando Polledo says:

    Hola, estube leyendo tu post y me parecio muy bien lo del reporte, quisiera ver si me puedes ayudar, tengo una aplicacion de escritorio y en un formulario quiero mostrar el reporte llamado Rporte1.rdlc ya me muestra los datos de la tabla pero no se como porque razon no hace caso a la consulta sql que le envio y para mas detalle pongo mi codigo para ver si me puedes ayudar, gracias

    BindingSource bindingSource1 = new BindingSource();
    string consulta = «»;

    consulta = «SELECT EMPEÑOS.id_empeño, PRENDAS.id_prenda, PRENDAS.tipo, PRENDAS.subtipo, PRENDAS.descripcion, PRENDAS.calidad, PRENDAS.peso,PRENDAS.mutuo, PRENDAS.avaluo FROM EMPEÑOS INNER JOIN PRENDAS ON EMPEÑOS.prenda1 = PRENDAS.id_prenda WHERE (PRENDAS.tipo = ‘Joyeria’)»;

    string cadena = obj.Cadena;
    SqlConnection olecn = new SqlConnection(cadena);
    SqlCommand olecmd1 = new SqlCommand(consulta, olecn);
    DataSet1 ds = new DataSet1();
    SqlDataAdapter a = new SqlDataAdapter(olecmd1);
    DataTable dt = new DataTable();
    a.Fill(dt);
    dt = ds.Tables[«PRENDAS»];
    bindingSource1.DataSource = dt;
    dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
    dataGridView1.DataSource = bindingSource1;
    ReportDataSource datasourse = new ReportDataSource(«DataSet1_PRENDAS», dt);
    reportViewer1.LocalReport.DataSources.Add(datasourse);
    reportViewer1.RefreshReport();

    • johnbarquin says:

      Prueba quitarle esta linea:

      dt = ds.Tables[«PRENDAS»];

      pues ya el a.Fill (dt) solamente, debe llenar el DataTable con los datos de tu consulta.

      • Armando Polledo says:

        Hola, Quite la linea pero sigue sin funcionar la consulta no se que pueda estar mal en el codigo ya que hace la consulta pero no la muestra en el reporte.

      • Juan Pedro Barquin says:

        Uhmmm mira, antes de agregar el nuevo ReportDataSource a la colección de DataSources del informe, quizás tengas que vaciarla primero, pues debe estar tomando la implícita que fue la ficticia que pusimos en la definición del informe y que por supuesto no tiene datos. Quedaría asi:

        ReportDataSource datasourse = new ReportDataSource(“DataSet1_PRENDAS”, dt);
        reportViewer1.LocalReport.DataSources.Clear(); // <<==== AGREGAR ESTA LINEA
        reportViewer1.LocalReport.DataSources.Add(datasourse);

  17. Jhon Alexis says:

    Muy buen ejemplo, pero tengo una duda y la quisiera comentar con ustedes:

    Estoy trabajando con Visual Basic .net, en visual estudio 2008.

    El tema es que el reporte, por algun motivo no se ve. He realizado pruebas, agregando errores forzados, pero aun asi no arroja el error (como por ejemplo poner otra extencion al reporte).

    He analizado el codigo y no puedo encontrar el error. Por favor hechenme una mono, gracias.

    Public Function RptProve() As DataTable

    Dim Sql As String
    Sql = «SELECT rutprov,prov,Direprov,ciudad,fonoprov FROM proveedores»

    Try
    Dim DA As New MySqlDataAdapter(Sql, Cnn)
    Dim DS As New DataSet

    DA.SelectCommand.CommandType = CommandType.Text
    DA.Fill(DS, «Proveedores»)
    Return DS.Tables(«Proveedores»)
    Catch
    MsgBox(«Existen problemas»)
    End Try

    End Function

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim rds As ReportDataSource = New ReportDataSource()
    rds.Name = «DSProve_DTProv»
    rds.Value = RptProve()
    RVProve.LocalReport.DataSources.Clear()
    RVProve.LocalReport.DataSources.Add(rds)
    RVProve.LocalReport.ReportPath = «ProveRpt.rdlc»

    RVProve.LocalReport.Refresh()

    End Sub

  18. Julio César Briceño says:

    Muy bueno este artículo. Excelente. Gracias!!!!

    Lo único que me faltaba era el import «Imports Microsoft.Reporting.WebForms»

    Una pregunta. Sabrás si se puede capturar el evento click sobre una fila y extraer el valor de algunos campos de la fila?

  19. Manuel says:

    EXCELENTE EJEMPLO, ESTOY COMENZANDO EN ESTO DE REPORTIN SERVICE, HE SEGUIDO LOS PASOS DEL EJEMPLO, Y TENGO EL SIGUIENTE PROBLEMA:
    EN MODO DE DISEÑO DEL SITIO WEB EL INFORME SE CARGA CORRECTAMENTE, PERO AL COMPILAR Y SUBIR AL SITIO WEB, NO CARGA EL INFORME Y NO SE CUAL ES EL ERROR. SI ALGUIEN ME PUEDE AYUDAR LES AGRADESCO

  20. Silvi says:

    Saludos,
    Si alguien me puede ayudar por favor mi problema es el siguiente..
    estoy haciendo un reporte con xtrareport y punto net en el cual coloco una imagen cualquiera, la imagen no esta en la base sino en un directorio, en en momento que visualizo el reporte esta la imagen, pero le ato mi reporte a un aspx y la imagen no aparece…
    gracias por su ayuda.

  21. eckos says:

    nadie responde!!!! de que sirve el foro???

  22. fg1010 says:

    Saludos

    Me gusto mucho el tutorial, quisiera saber como se hace lo mismo al utilizar tablas con un join entre 2 tablas !!

    • Juan Pedro Barquin says:

      Si, de hecho el ejemplo mostrado usa JOINs con varias tablas, la preparación de la fuente de datos (DataSet) para el informe puede ser todo lo complicada que sea necesario; lo importante es la correcta asociación de los campos de este resultado final con los elementos del informe.

  23. german says:

    para ver sime pueden ayudar:

    soy principiante para la realizacion del reportes en visual basic 2008
    ya hice la prueba de como funciona el proceso realizando el proceso mediante el asistente de oriegne de datos.
    lo que yo quiero es realizar el reporte mediante codigo, he probado con los codigos que algunos compañeros me ha dado pero nada. el error es el siguiente .
    Error 1 El objeto ‘table1’ de tipo table se encuentra en el cuerpo del informe, pero el informe no tiene ningún conjunto de datos. No se permiten regiones de datos en informes sin conjuntos de datos. C:\Users\Adminitrador\Desktop\WindowsApplication2\WindowsApplication2\Report1.rdlc WindowsApplication2

    adjunto el codigo

    ‘ espacio de nombres de las librerias
    Imports System.Data ‘importa las librerias a trabajar con los datos
    Imports System.Data.SqlClient ‘importa el cleinete que trabaja con losdatos
    Imports Microsoft.Reporting.WinForms
    Public Class Form1
    Dim colBotones As New DataGridViewButtonColumn ‘CREO LA VARIABLE DE TIPO DE BOTON EL DATAGRID
    Dim imprimir As New BindingSource
    Dim sql As String
    Dim imp As SqlCommand
    Dim datos As SqlDataAdapter
    Dim datos1 As DataSet
    Dim datasourse As ReportDataSource

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    sql = «select Nom_Paciente from tbl_paciente»
    imp = New SqlCommand

    imp.CommandType = CommandType.Text
    imp.CommandText = sql
    imp.Connection = Cn
    datos = New SqlDataAdapter(imp)
    datos1 = New DataSet
    datos.Fill(datos1, «tbl_paciente»)
    imprimir.DataSource = datos1
    datasourse = New ReportDataSource(«DataSet1», datos1)
    ReportViewer1.LocalReport.DataSources.Clear()
    ReportViewer1.LocalReport.DataSources.Add(datasourse)
    ReportViewer1.RefreshReport()

    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Call ConectarDB()
    ReportViewer1.LocalReport.ReportPath = «Report1.rdlc»
    Me.ReportViewer1.RefreshReport()

    End Sub
    End Class

    espero una colaboracion por parte de ustedes.

  24. VHSO says:

    Hola amigo excelente tutorial pero por favor podrias indicar como hacer un reporte con parametros
    gracias

  25. francisco says:

    Hola, muy bueno elaporte de verdad, a mi me sirvio muchisimo la aplicacion con matrices. creo que ahora he aprendido muchisomo de report viewer, pero tengo una pregunta y ojala puedan contestarmela lo mas rápido posible, resulta que hice mi aplicacion en asp.net 2005 y c# con reportes en report viewer, eso en win 2003 server me funciona barbaro, pero en linux centos 5.4 como le hago para que funciones los reportes hechos con reportviewer, si hay alguien que me pueda ayudar, se lo agradecería.
    Tambien respondiendo a la pregunta de VHSO, solo te vas al menu dentro del reporte, y seleccionas report parameters y añades los parametros que desees por ejemplo docente (nombre del parametro) seleccionas el tipo de parametro y listo ahora, para pasarle desde asp.net con codigo c# lo ago asi
    ReportParameter param1 = new ReportParameter(«docente», ddlProfesor.SelectedItem.ToString());
    ReportParameter[] p1 ={ param1 };
    rpvNotasHQ1.LocalReport.SetParameters(p1);
    ddlProfesor es el control desde donde paso el parametro y listo ya solo debes añadir un textbox y
    agregar esta linea en el
    =Parameters!docente.value

    ojala sea de ayuda

  26. Rolph says:

    En que parte del reporte defino la funcion RowNumber(Nothing) o donde la configuro?

  27. Rolph says:

    Disculpa soy nuevo con el manejo de este control. Es posible colocar en cajas de texto datos distribuidas sobre mi repote datos que obtengo de una consulta?

  28. Ezequiel says:

    a mi da un problemita, yo quiero mostrarlo en una aplicacion desktop, pero no reconoce la funcion ReportDataSource rds = new ReportDataSource(); me dice que no puede hayarlo, me falta alguna directiva para que lo reconozca???

  29. Ezequiel says:

    esto es lo que estoy haciendo, pero no me esta cargando los datos y no logro identificar que es lo que esta mal, es con una base de datos en acces
    co-> es un objeto de una clase conexion donde se conecta a la base de datos
    public DataSet Calculardataset()
    {
    string cadenainstruccionSQL = «select * from Acta_Consumo where Acta_Consumo.Id=4»;
    co.oconectar.Open();
    co.ocomando = co.oconectar.CreateCommand();
    co.ocomando.CommandText = cadenainstruccionSQL;
    OleDbDataAdapter adapter = new OleDbDataAdapter(co.ocomando);

    DataSet datareport = new DataSet();
    adapter.Fill(datareport, «tablareport»);
    co.oconectar.Close();
    return datareport;
    }

  30. Ezequiel says:

    no logro encontrar la parte de sección de DataSets del RDLC

  31. Jorge says:

    Tengo un problema no reconoce la funcion ReportDataSource rds = new ReportDataSource(); me dice que no puede hayarlo

  32. Alejandro says:

    Muy buen aporte… gracias… pero necesito unas ayudas adicionales,pues tengo una aplicación web la cual cuenta con reportes, por favor necesito ejemplos sobre el Microsoft ReportViewer pero usando parametros, en este caso que el parametro se obtenga de un DropDownList.
    La aplicación está en 3 capas.
    Gracias nuevamente.

  33. Francisco Rubio says:

    Gracias. Buen post. Me ha sido util

  34. Alejandro Sepúlveda Cuartas says:

    Juan Pedro, realmente tu aporte ha sido muy valioso y me dio lo que realmente quería hacer.
    Lo único a lo que no le pude llegar fue a hacer el DataSet “ficticio”, así que esto lo hice de una forma mucho más complicada, pero que al final también me funcionó.
    Si alguien pudiera darme un enlace de un video para entender bien como se hace el DataSet «ficticio» lo agradecería mucho. Yo uso C# 2010, por aquello de que este dato sea importante.

  35. johnarevalo says:

    Con respecto a la pginacion cuando le cambias la propiedad de AsyncRendering=False y SizeToReportContent=True para que no halla problema con la paginacion debes colocar llamar al metodo protected void MostrarInforme() en el evento init del reportviewer

  36. hackcgm says:

    HOLA A TODOS

    COMO PUEDO PASAR UN INFORME.RDLC A U PRINTPREVEWDIALOG Y UN PRINTDOCUMENT

  37. Chaper says:

    Muy buen material, excelente, ahora bien, el ejemplo que usas es los reportes locales (.rdlc), ahora bien, ¿hay alguna manera de realizar misma funcionalidad, pero para un reporte remoto?, es decir un archivo .rdl, que esta alojado en un servidor de informe, y se requiere que el origen de datos cambie dinamicamente. Gracias de antemano.

  38. hackcgm says:

    hay alguna manera de que el usuario seleccione los campos que quiere que aparecen en el informe desde un form de visual studio………….

  39. AleBerto says:

    Buenoas, estoy teniendo un problema y no se bien como solucionarlo.
    Realize una aplicacion Web que necesita mostrar un formulario para imprimir. Para ello completa un formulario y al enviar habro otra pagina web con un reportViewer. En en load de la pagina de reporte seteo el reporte que es de tipo LocalReport, ya que por un solo reporte me parecia mas complicado configurar un Servidor de Informes.
    El problema que el reporte que quiero generar es de Solicitud de Usuario, entonces esta dentro de una seccion del Sitio Web donde no necesita loguearse. El problema es el siguiente: Con el codigo que copio abajo cuando ejecuto el reporte no termine de generarse nunca y aveces me pide (en el reporte!) usuario y contraseña:

    ReportViewer1.ShowCredentialPrompts = false;
    // Habilitar hipervínculos para manejar clic en el ID del cliente

    // Necesario ya que la imagen del logotipo
    ReportViewer1.LocalReport.EnableExternalImages = true;
    ReportViewer1.LocalReport.ExecuteReportInCurrentAppDomain(System.Reflection.Assembly.GetExecutingAssembly().Evidence);
    ReportViewer1.LocalReport.SetParameters(rp);
    ReportViewer1.LocalReport.Refresh();
    en cambio si le agrego la siguiente linea funciona correctamente donde ‘2035425435244’ es el id de usuario que corrresponde con el CUIT

    -FormsAuthentication.SetAuthCookie(«2035425435244», false);

    Obviamente debe ser un tema de Seguridad pero no se como resolverlo, ya que con la solución que le encontré(lo de agregar esa línea) luego entra al sitio a la parte donde no debería entrar si no tiene autorización.

    Ademas en el web.config tengo la exclusion.

    Si alguien puede ayudarme. Muchas gracias

  40. Junior says:

    Juan criei um dataset com xml e queria no report vincular esse dataset sendo que quando no report seleciono reportdata new dataset esse dataset nao aparece, criei esse dataset no projeto na pasta relatorio/xds.
    Ou só posso vincular o dataset vindo de um tableadapter ?

  41. Nico Dogi says:

    Hola que tal, estoy haciendo un proyecto en Visual Studio 2010, donde tendo un reporte rdl creado con ReportBuilder 2.0 en ProcessingMode=Local. Mi App es en WinForms, el tema es el siguiente:
    Ej: tengo un datatable con clientes como filas, y tengo que generar un reporte por cada linea del datatable, el problema es que cuando el asigno al ReportViewer el datatable solo me un reporte con los datos del primer cliente. Yo quisiera que me genere tanto reportes como filas tenga el datatable y despues mandar a imprimir.

    Alguna sugerencia?? no logro dar con la solucion.

    Muchas Gracias

  42. johan says:

    Buen dia, excelente post, pero tengo un problema, estoy trabajando con windows form, cuando carga el reporte no muestra nada, ni dice que se esta generando el reporte. Utilice la segunda opcion creo el archivo xml con un sp de la base de datos que contendra la extructura donde estaran los datos, Ya verifique y si esta llegando el dataset con la informacion que necesito. Sin embargo no lo muestra. Podrian ayudarme por favor. Muchas gracias.

  43. LRE says:

    Mi problema es el siguiente, necesito que en el reportviewer los objetos se los pueda ubicar en diferente posició per en tiempo de ejecución, ya que en crystal reports si hay como hacer eso, alguien podría ayudarme?

  44. Luis says:

    Saludos tienes un ejemplo por favor

  45. sandra says:

    Hola
    A alguien no le salio un error como error al procesar el informe. Dataset1

  46. hola, teng un problema, el informe sale con los titulos pero los datos no se llenan, no sabras que pueda ser??

  47. luismlgn says:

    Por favor ayudenme, al cargar el reporte sale en blanco y solo aparece «No se ha proporcionado ninguna instancia de origen de datos para el origen de datos «DataSet1», a que se puede deber esto???

  48. Augusto Eduardo says:

    Estimado amigo es posible que pueda imprimir el reporte desde un botón ajeno a reportviewer?

  49. Cesar says:

    Hola, tengo un proyecto Web con .Net 2008, cuando ejecuto el ReportViewer en modo Local me muestra los datos pero cuando lo subo al servidor me muestra el reporte pero sin datos. No me muestra ningún mensaje de error. Si me pueden ayudar lo agradecería mucho!
    Att: Cesar Osorio

  50. Cesar says:

    Solucionado, el administrador del servidor tenia los reportes bloqueados.

  51. Kam says:

    Realice un Reporte con ReportsPreviewer me genera y todo me sale perfecto pero al momento de crear algun filtro no me visualiza los metodos.

    este codigo lo estoy ingresando en un boton para visualizar y agregar parametros.

    Me.SqlDataSource1

    Me.ReportViewer1.

  52. Alma says:

    Muchas gracias Brother, me has salvado la semana

  53. Larr says:

    Gracias por la publicación, yo aplique el segmento de código MostrarInforme() para crear y cargar en tiempo de ejecución los rdlc, generar pdfs y exportarlos, utilice un SP para asignarlo al .value del ReportDataSource.

  54. eliud says:

    Una ayuda, tengo un report viewer, estoy manejando imagenes en barrido, osea meto una imagen en un lisp y el reporte me salen 3 fotos hacia abajo y esta bien ahora habra una forma de que el barrido no sea habia abajo, si no lateral, ya le he buscado y no encuentro nada, gracias

  55. Hernán says:

    Hola johnbarquin,
    Muy bueno tu aporte !!!!.
    Estoy desarrollando una aplicación WinForm con ReportViewer para datos dinámicos y tengo el siguiente problema :
    Dentro del archivo .rdlc inserto un objeto tabla, coloco el nombre de las columnas.
    No entiendo bien donde debo colocar el dataset, si es dentro del informe ó dentro del form que contiene al objeto reportviewer. Porque cuando lo coloco dentro del informe no lo enlazo a ningún origen de datos porque lo hago desde el form pero no puedo compilar el proyecto porque falta el origen de datos.
    Muchas gracias.

  56. Ignacio says:

    Muy buen aporte
    Una pregunta si por algun motivo se requiere mas de una consulta por ejemplo 2 consultas(Cabezera y Detalle), tendria 1 DATASET con 2 DATATABLES, entonces como prodria hacerle para asignarle al LocalReport.DataSources el «dataset» y NO el datatable(0) o tedria que agregar los 2 datatables datatable(1) y datatable(2) ???

    Para ver si me puedes ayudar y explicar un poco mas ya que la experiencia que tengo es muy poca.

    Gracias

  57. Erizo says:

    Interesante Codigo lo pruebo para hacer una dll para reportes si todo sale bien retroalimento
    saludos

  58. Juan Del Rosario says:

    Saludos, compañeros:

    Seguí los pasos de esta entrada para un reporte con la versión de Visual Studio 2012, pero no me está funcionando. Se muestra el viewer en blanco, aun cuando el DataTable que le asigno tiene datos y el DataSet tiene el mismo nombre en el reporte. Alguna Idea:

    Public Sub CargaReporteTickets(Tick_Grupo As String)
    Try
    Dim ObjTicket As New clTicket
    Dim ds As New DataSet
    ds = ObjTicket.ConsultarTicket(Tick_Grupo)
    Dim rds As New ReportDataSource()
    rds.Name = «SP_ReporteTicket»
    ds.Tables(0).TableName = «SP_ReporteTicket»
    rds.Value = ds.Tables(0)
    RV.LocalReport.DataSources.Clear()
    RV.LocalReport.DataSources.Add(rds)
    RV.LocalReport.ReportPath = «ReporteTickets.rdlc»
    RV.LocalReport.Refresh()
    Catch ex As Exception
    MessageBox.Show(«Ha ocurrido un error cargando los tickets.» + ex.Message())
    End Try
    End Sub

    Saludos,

  59. maybar2 says:

    me sale este error alguien que pueda ayudarme a resolverlo

    Se ha producido un error durante el procesamiento local de informes.
    No se ha especificado la definición del informe ‘ReportP’
    Referencia a objeto no establecida como instancia de un objeto.

Replica a Cesar Cancelar la respuesta