ReportViewer y Rdlc, ejemplo Factura (datos fijos) Hola a todos: El siguiente articulo pretende mostrar la manera de crear un reporte local usando ReportViewer y Local Report o Rdlc enlazando su origen datos (DataSource) a una fuente proveniente de una Lista Genérica de propiedades. Como se que esto puede resultar un tema demasiado complicado cuando no se tiene experiencia en el manejo de reportes tratare de que el articulo sea lo mas descriptivo posible y para ello me apoyare en la mayor cantidad de imágenes posibles, traten de realizar el ejemplo siguiendo el tutorial, si un paso no les queda claro siéntanse con toda confianza de hacer las consultas necesarias, al final del articulo tendrán el link de descarga del proyecto de ejemplo. Los datos los enviaremos desde un formulario simulando ser los datos de una Factura comercial, que contiene Datos del cliente y los artículos adquiridos. Bien, comencemos creando un Formulario y arrastrando los controles necesarios hasta obtener un formulario como este:
Agregue un segundo formulario, llámelo FacturaRpt.cs este contendrá el control ReportViewer al cual enlazaremos el LocalReport, asi que agregue uno arrastrándolo desde el cuadro de herramientas.
Agregue un LocalReport, deje el nombre default:
Ahora, crearemos las clases contenedoras de las entidades, recuerde que una entidad esta compuesta por campos y propiedades. Inserte una nueva clase y nómbrela EArticulo, la cual contendrá todas las propiedades de la entidad Articulo, la clase deberá de quedar con esta estructura:
Código C #: namespace ReportViewerInvoiceReport_CSharp { public class EArticulo { public int Numero { get get; ; set set; ; } public string Upc { get get; ; set set; ; } public string Descripcion { get get; ; set set; ; } public decimal Piezas { get get; ; set set; ; } public decimal Precio { get get; ; set set; ; } public decimal Importe { get get; ; set set; ; } } }
C ód ódig ig o Vb.Net: Vb.Net: Public Class EArticulo Public Property Numero() As Integer Public Property Upc() As String Public Property Descripcion() As String Public Property Piezas() As Decimal Public Property Precio() As Decimal Public Property Importe() As Decimal
End Class Después inserte una nueva clase y nómbrela EFactura, esta clase contendrá todas las propiedades del encabezado de la factura, la clase deberá de quedar con esta estructura:
Código C #: using System; using System.Collections.Generic; namespace ReportViewerInvoiceReport_CSharp { public class EFactura { public int Numero { get get; ; set set; ; } public string Nombre { get get; ; set set; ; } public string Rfc { get get; ; set set; ; } public string Direccion { get get; ; set set; ; } public decimal Subtotal { get get; ; set set; ; } public decimal Iva { get get; ; set set; ; } public decimal Total { get get; ; set set; ; } public DateTime FechaFactur FechaFacturacion acion { get get; ; set set; ; } //Creamos una lista con una nueva Instancia de la clase Articulo //esta lista contendra el detalle de la factura public List List<
> Detail = new List List< (); >(); } }
C ód ódig ig o Vb.Net: Vb.Net: Imports System.Collections.Generic Public Class EFactura Public Property Numero() As Integer Public Property Nombre() As String Public Property Rfc() As String Public Property Direccion() As String Public Property Subtotal() As Decimal Public Property Iva() As Decimal Public Property Total() As Decimal Public Property FechaFacturacion() As DateTime 'Creamos una lista con una nueva Instancia de la clase Articulo 'esta lista contendra el detalle de la factura Public Detail As New List List( (Of EArticulo EArticulo)() )() End Class Configurar el Reporte del informe “Report1.rdlc” Para poder usar las clases de EFactura para llenar el Encabezado del reporte y EArticulo para el detalle del mismo, primero debemos de generar el proyecto, para ello localice el menú Generar – –> > Generar Solución Establecer la fuente de datos del Reporte Active el cuadro Datos del informe, Menú Ver – –> >Datos del informe
Establezca el Nombre del conjunto de datos y haga click sobre el botón Nuevo:
Seleccione Objeto y haga Click sobre el botón S ig uiente:
Seleccione la clase EFactura, recuerde que esta clase contiene las propiedades para el encabezado de la factura y haga Click sobre el botón Finalizar (Si no hubiera generado el proyecto estas clases no estarían visibles, así que si no las ve por favor cierre la ventana y genere la solución):
Observe que ya tiene una fuente de datos seleccionada, solo haga Click en el botón A ceptar :
Bien, ya tiene una Fuente de datos configurada:
Siga los mismos pasos para agregar la fuente de datos para el detalle del reporte solo que ahora seleccionara la clase EArticulo, al final tendrá un resultado como el siguiente:
Configurar tamaño y encabezado del informe Active la regla del informe para ello menú Informe –> Regla Configure el tamaño del informe, menú Informe –> P ropiedades del informe
Un punto muy importante en este paso es tener presente el Ancho o alto del reporte dependiendo que tipo de orientación se haya elegido, en este caso el ancho es lo que interesa, considere que tiene un ancho máximo de 21.59 cm. a este espacio le restara el valor total de los márgenes que son 2.0 cm en total ya que configuro un margen de 0.5 cm, dando un espacio de trabajo real disponible de 19.59 cm., si en el diseño de nuestro reporte nos pasamos de este espacio disponible nuestro reporte en lugar de mostrarnos una hoja nos mostrar ara dos, normalmente la segunda hoja sin o con pocos datos. Bien, continuemos… Agregue un encabezado de reporte, menú Informe –> Agregar encabezado de pagina Active el cuadro de herramientas, menú Ver –> C uadro de herramientas :
Arrastre tantos Cuadros de texto como se requieran, recuerde que nuestros datos provienen de una clase, entonces por cada campo-propiedad de la clase tiene que crear un control Cuadro de texto para poder visualizar el dato…esto de crear un control por cada propiedades de la clase origen es únicamente para este reporte, en realidad usted puede elegir que datos mostrar y cuales no. Configurar control cuadro de texto:
Click derecho sobre el control cuadro de texto que deseemos configurar: Recuerde que establecer un nombre a los controles que vayamos utilizando es de vital importancia porque será en base a este como los identificaremos, en proyectos pequeños tal vez no tenga problemas si deja los nombres asignados por default pero, en proyectos grandes esta mala practica nos provocara constantes dolores de cabeza, entonces, nunca olvide ponerle un nombre a los controles. Considere que el nombre debe de identificar fácilmente al control al que hace referencia y al dato que contendrá o al cual estará relacionado, en este caso txtFactura es muy descriptivo, ya que se entiende que es un control textBox o cuadro de texto y que contendrá el numero de factura. Para definir el origen del dato que mostrara el control cuadro de texto despliegue el ComboBox Valor, vera que este estará cargado con las propiedades de las clases las cuales definimos como fuente de datos, no le será difícil identificar a que clase pertenece cada una ya que al final podra ver el nombre que le puso al origen de datos.
Desactivar la casilla “ Permitir aumentar el alto ” puede resultar muy importante para conservar un buen diseño, tener activada esta casilla permite que el control cambie de tamaño en tiempo de ejecución adecuándose al tamaño del valor que contiene, modificando con esto el diseño hasta el punto de generar hojas innecesarias.
En este ejemplo el campo Factura será del tipo numérico por lo cual para conservar un formato de numero correcto, tendrá que configurar el lenguaje que utilizara el campo, para mi ubicación (México) la configuración de lenguaje será “ es-Mex ”, para configurar esta propiedad:
S elecci one el contr ol cuadro de texto –> Presi one F4:
Si no hiciera esto, un formato numérico podría no mostrarse correctamente por ejemplo la cantidad Mil doscientos cincuenta y seis con cincuenta y seis decimales en México será 1,256.56 pero en España se escribiría de esta manera 1.256,56. Esta configuración debemos de hacerla aun si en la clase Main de nuestro proyecto hayamos definido un lenguaje de manera predeterminada. Agregar parámetros al Reporte: Para abarcar mas sobre el tema de ReportViewer y local report, subamos un poco mas el nivel de nuestro proyecto agregando parámetros al mismo, esto no siempre es necesario así que en
este articulo solo lo haremos para fines ilustrativos, es decir, para cuando lleguemos a necesitarlo tendremos el conocimiento disponible de como usarlos. En el Datos del informe –> Click derecho sobre Parametros –> A g reg ar parametro :
De nuevo, recuerde que nombrar correctamente a cada control que agregamos es de vital importancia:
Agregue un nuevo parámetro y nómbrelo parametroEmpresa.
Ahora, arrastre dos controles Cuadro de texto al informe, y vaya a las propiedades para configurar el valor a mostrar:
Haga lo mismo para el segundo control agregado, veamos como va nuestro diseño del informe:
Para el detalle del informe, agregue un Tabla arrastrándola desde el cuadro de herramientas, vaya a las propiedades de la tabla recién agregada, ubique la propiedad DataSetName par establecer el origen de datos y seleccione Detalle, recuerde que ese fue el nombre que establecimos al origen de datos:
Agregue las columnas que falten para completar el cuerpo del informe, para ello haga Click derecho sobre la tabla, Insertar columna, Izquierda o derecha. Después establezca el valor que mostrara cada columna, para ello tiene dos opciones, seleccionar el valor desde el icono que vera en la esquina superior derecha de cada celda o ir a propiedades del cuadro de texto tal cual como lo hizo anteriormente:
Establezca el tamaño de fuente, borde, tipo de dato, lenguaje a utilizar (recuerde lo comentado anteriormente sobre el formato de numero/moneda) ¿Como va nuestro diseño de informe?
Si tienen un resultado como este, pueden dar su tarea por terminada en cuanto al diseño del informe si aun no lo logran, todo es cuestión que revisen como configurar un control TextBox o cuadro de texto como gusten llamarlo y ponerse a ver Alineación, tipo de fuente, borde, relleno, etc… Hasta aquí daremos por terminado nuestro diseño, ahora vayamos a: Establecer una Lista Genérica como DataSource de un local report: Ubique el Formulario contenedor del ReportViewer llamado FacturaRpt, seleccione el icono superior derecho del reportViewer –> Seleccione el local report que utilizaremos (el único que hemos diseñado)
Una vez echo lo anterior, genere el evento Load del Formulario, para ello puede hacer doble click sobre la barra de titulo o seleccionar el form y presionar la tecla de función F4, esto abrirá la caja de propiedades, en la par te superior podrá ver un icono con forma de “rayo” de color amarillo, haga click sobre el para ver los eventos que implementa el control, después ubique el Evento que le interese implementar en este caso nos interesa el evento “Load”. Copie y pegue el siguiente código:
Código C #: using System; using System.Collections.Generic; using System.Windows.Forms;
using Microsoft.Reporting.WinForms; namespace ReportViewerInvoiceReport_CSharp { public partial class FacturaRpt : Form { // //Cree dos listas una para el Encabezado y otra para el detalle // public List Invoice = new List(); public List Detail = new List(); // //Cree las propiedades publicas Titulo y Empresa // public string Titulo { get; set; } public string Empresa { get; set; } public FacturaRpt() { InitializeComponent(); } private void FacturaRpt_Load(object sender, EventArgs e) { //Limpiemos el DataSource del informe reportViewer1.LocalReport.DataSources.Clear(); // //Establezcamos los parámetros que enviaremos al reporte //recuerde que son dos para el titulo del reporte y para el nombre de la empresa // ReportParameter[] parameters = new ReportParameter[2]; parameters[0] = new ReportParameter("parameterTitulo", Titulo); parameters[1] = new ReportParameter("parameterEmpresa", Empresa); // //Establezcamos la lista como Datasource del informe // reportViewer1.LocalReport.DataSources.Add(new ReportDataSource("Encabezado", Invoice)); reportViewer1.LocalReport.DataSources.Add(new ReportDataSource("Detalle", Detail)); // //Enviemos la lista de parametros // reportViewer1.LocalReport.SetParameters(parameters); // //Hagamos un refresh al reportViewer // reportViewer1.RefreshReport(); } } }
C ódig o Vb.Net: Imports Microsoft.Reporting.WinForms Public Class FacturaRpt
' 'Cree dos listas una para el Encabezado y otra para el detalle ' Public Invoice As New List(Of EFactura)() Public Detail As New List(Of EArticulo)() ' 'Cree las propiedades publicas Titulo y Empresa ' Public Property Titulo() As String Public Property Empresa() As String Private Sub FacturaRpt_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 'Limpiemos el DataSource del informe ReportViewer1.LocalReport.DataSources.Clear() ' 'Establezcamos los parametros que enviaremos al reporte 'recuerde que son dos para el titulo del reporte y para el nombre de la empresa ' Dim parameters As ReportParameter() = New ReportParameter(1) {} parameters(0) = New ReportParameter("parameterTitulo", Titulo) parameters(1) = New ReportParameter("parameterEmpresa", Empresa) ' 'Establezcamos la lista como Datasource del informe ' ReportViewer1.LocalReport.DataSources.Add(New ReportDataSource("Encabezado", Invoice)) ReportViewer1.LocalReport.DataSources.Add(New ReportDataSource("Detalle", Detail)) ' 'Enviemos la lista de parametros ' ReportViewer1.LocalReport.SetParameters(parameters) ' 'Hagamos un refresh al reportViewer ' ReportViewer1.RefreshReport() End Sub End Class
Hagamos lo ultimo que falta, enviar los datos desde el formulario principal: Genere el Evento load del Formulario principal,
Después de generado el evento trate de seguir estas líneas de código, escriba linea por linea si copia y pega será mas complicado que comprenda (suponiendo que su experiencia en desarrollo no es amplia):
Código C #: using using using using
System; System.Collections.Generic; System.Linq; System.Windows.Forms;
namespace ReportViewerInvoiceReport_CSharp { public partial class Form1 : Form { public Form1() { InitializeComponent(); } /// /// Funcion encargada de llenar el control DataGridView /// José Luis García Bautista /// /// Una lista generica de la clase artículo private static List FillDgv() { // //Cree una lista generica de la entidad EArticulo // List listaArticulos = new List(); // //Instancie la clase EArticulo para agregar datos a la lista // EArticulo item = new EArticulo {
//Establezca valores a cada una de las propiedades Numero = 1, Upc = "7501020405680", Descripcion = "Descripción del artículo 1", Piezas = 6, Precio = new decimal(12.50), Importe = (decimal)(6 * 12.5), }; // //Agregamos el Item a la lista // listaArticulos.Add(item); EArticulo item1 = new EArticulo { Numero = 2, Upc = "7501040805610", Descripcion = "Descripción del artículo 2", Piezas = 3, Precio = new decimal(22.50), Importe = (decimal)(3 * 22.5), }; listaArticulos.Add(item1); EArticulo item2 = new EArticulo { Numero = 3, Upc = "0412200805610", Descripcion = "Descripción del artículo 3", Piezas = 20, Precio = new decimal(52.80), Importe = (decimal)(20 * 52.80), }; listaArticulos.Add(item2); return listaArticulos; } private void Form1_Load(object sender, EventArgs e) { // //La funcion GenerateNumber() se utiliza unicamente para generar un Número //aleatorio que simulara ser el numerod e factura txtnumero.Text = GenerateNumber().ToString(); //Establecemos la propiedad AutoGenerateColumns en False para evitar que se agreguen //nuevas columnas a la derecha de las que creamos en tiempo de diseño. // dgvdetalle.AutoGenerateColumns = false; // //Establecemos el DataSource del control DataGridView // dgvdetalle.DataSource = FillDgv(); //
//Mapeamos las propiedades de la clase devuelta por la Funcion FillDgv() //recuerde que esta funcion devuelve una lista del tipo EArticulo // dgvdetalle.Columns["columnNumero"].DataPropertyName = "Numero"; dgvdetalle.Columns["columnUpc"].DataPropertyName = "Upc"; dgvdetalle.Columns["columnDescripcion"].DataPropertyName = "Descripcion"; dgvdetalle.Columns["columnPiezas"].DataPropertyName = "Piezas"; dgvdetalle.Columns["columnPrecio"].DataPropertyName = "Precio"; dgvdetalle.Columns["columnImporte"].DataPropertyName = "Importe"; // //Hacemos las sumatorias usando un método de extensión de Linq // decimal sum = FillDgv().Sum(x => x.Importe); decimal iva = (Math.Round(((sum / 116) * 16), 2)); decimal subtotal = Math.Round(sum - iva, 2); txttotal.Text = Convert.ToString(Math.Round(sum, 2)); txtiva.Text = Convert.ToString(iva); txtsubtotal.Text = Convert.ToString(subtotal); } private static int GenerateNumber() { Random rdm = new Random(); return rdm.Next(); }
private void InvoiceGenerate() { // //Hacemos una instancia de la clase EFactura para //llenarla con los valores contenidos en los controles del Formulario EFactura invoice = new EFactura(); invoice.Numero = Convert.ToInt32(txtnumero.Text); invoice.Nombre = txtnombre.Text; invoice.Rfc = txtrfc.Text; invoice.Direccion = txtdireccion.Text; invoice.FechaFacturacion = dtpfecha.Value.Date; invoice.Subtotal = Convert.ToDecimal(txtsubtotal.Text); invoice.Iva = Convert.ToDecimal(txtiva.Text); invoice.Total = Convert.ToDecimal(txttotal.Text); //Recorremos los Rows existentes actualmente en el control DataGridView //para asignar los datos a las propiedades foreach (DataGridViewRow row in dgvdetalle.Rows) { EArticulo article = new EArticulo(); //
//Vamos tomando los valores de las celdas del row que estamos //recorriendo actualmente y asignamos su valor a la propiedad de la clase intanciada // article.Numero = Convert.ToInt32(row.Cells["columnNumero"].Value); article.Upc = Convert.ToString(row.Cells["columnUpc"].Value); article.Descripcion = Convert.ToString(row.Cells["columnDescripcion"].Value); article.Piezas = Convert.ToDecimal(row.Cells["columnPiezas"].Value); article.Precio = Convert.ToDecimal(row.Cells["columnPrecio"].Value); article.Importe = Convert.ToDecimal(row.Cells["columnImporte"].Value); // //Vamos agregando el Item a la lista del detalle // invoice.Detail.Add(article); } // //Creamos una instancia del Formulario que contiene nuestro //ReportViewer // FacturaRpt frm = new FacturaRpt(); // //Usamos las propiedades publicas del formulario, aqui es donde enviamos el valor //que se mostrara en los parametros creados en el LocalReport, para este ejemplo //estamos Seteando los valores directamente pero usted puede usar algun control // frm.Titulo = "Este es un ejemplo de Factura"; frm.Empresa = "Este es un ejemplo del Nombre de la Empresa"; // //Recuerde que invoice es una Lista Generica declarada en el FacturaRtp, es una lista //porque el origen de datos del LocalReport unicamente permite ser enlazado a objetos que //implementen IEnumerable. // //Usamos el metod Add porque Invoice es una lista e invoice es una entidad simple frm.Invoice.Add(invoice); // //Enviamos el detalle de la Factura, como Detail es una lista e invoide.Details tambien //es un lista del tipo EArticulo bastara con igualarla // frm.Detail = invoice.Detail; frm.Show(); } private void btnImprimir_Click(object sender, EventArgs e)
{ InvoiceGenerate(); } } }
C ódig o Vb.Net: Public Class Form1 ''' ''' Funcion encargada de llenar el control DataGridView ''' José Luis García Bautista ''' ''' Una lista generica de la clase artículo Private Shared Function FillDgv() As List(Of EArticulo) ' 'Cree una lista generica de la entidad EArticulo ' Dim listaArticulos As New List(Of EArticulo)() ' 'Instancie la clase EArticulo para agregar datos a la lista ' 'Establezca valores a cada una de las propiedades Dim item As New EArticulo() item.Numero = 1 item.Upc = "7501020405680" item.Descripcion = "Descripción del artículo 1" item.Piezas = 6 item.Precio = New Decimal(12.5) item.Importe = CDec(6 * 12.5) ' 'Agregamos el Item a la lista ' listaArticulos.Add(item) Dim item1 As New EArticulo() item1.Numero = 2 item1.Upc = "7501040805610" item1.Descripcion = "Descripción del artículo 2" item1.Piezas = 3 item1.Precio = New Decimal(22.5) item1.Importe = CDec(3 * 22.5) listaArticulos.Add(item1) Dim item2 As New EArticulo() item2.Numero = 3 item2.Upc = "0412200805610" item2.Descripcion = "Descripción del artículo 3" item2.Piezas = 20 item2.Precio = New Decimal(52.8) item2.Importe = CDec(20 * 52.8) listaArticulos.Add(item2) Return listaArticulos End Function
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load '
'La funcion GenerateNumber() se utiliza unicamente para generar un Número 'aleatorio que simulara ser el numerod e factura txtnumero.Text = GenerateNumber().ToString() 'Establecemos la propiedad AutoGenerateColumns en False para evitar que se agreguen 'nuevas columnas a la derecha de las que creamos en tiempo de diseño. ' dgvdetalle.AutoGenerateColumns = False ' 'Establecemos el DataSource del control DataGridView ' dgvdetalle.DataSource = FillDgv() ' 'Mapeamos las propiedades de la clase devuelta por la Funcion FillDgv() 'recuerde que esta funcion devuelve una lista del tipo EArticulo ' dgvdetalle.Columns("columnNumero").DataPropertyName = "Numero" dgvdetalle.Columns("columnUpc").DataPropertyName = "Upc" dgvdetalle.Columns("columnDescripcion").DataPropertyName = "Descripcion" dgvdetalle.Columns("columnPiezas").DataPropertyName = "Piezas" dgvdetalle.Columns("columnPrecio").DataPropertyName = "Precio" dgvdetalle.Columns("columnImporte").DataPropertyName = "Importe" ' 'Hacemos las sumatorias usando un método de extensión de Linq ' Dim sum As Decimal = FillDgv().Sum(Function(x) x.Importe) Dim iva As Decimal = (Math.Round(((sum / 116) * 16), 2)) Dim subtotal As Decimal = Math.Round(sum - iva, 2) txttotal.Text = Convert.ToString(Math.Round(sum, 2)) txtiva.Text = Convert.ToString(iva) txtsubtotal.Text = Convert.ToString(subtotal) End Sub Private Shared Function GenerateNumber() As Integer Dim rdm As New Random() Return rdm.[Next]() End Function Private Sub InvoiceGenerate() ' 'Hacemos una instancia de la clase EFactura para 'llenarla con los valores contenidos en los controles del Formulario Dim invoice As New EFactura() invoice.Numero = Convert.ToInt32(txtnumero.Text) invoice.Nombre = txtnombre.Text invoice.Rfc = txtrfc.Text invoice.Direccion = txtdireccion.Text invoice.FechaFacturacion = dtpfecha.Value.[Date] invoice.Subtotal = Convert.ToDecimal(txtsubtotal.Text) invoice.Iva = Convert.ToDecimal(txtiva.Text) invoice.Total = Convert.ToDecimal(txttotal.Text)
'Recorremos los Rows existentes actualmente en el control DataGridView 'para asignar los datos a las propiedades For Each row As DataGridViewRow In dgvdetalle.Rows Dim article As New EArticulo() ' 'Vamos tomando los valores de las celdas del row que estamos 'recorriendo actualmente y asignamos su valor a la propiedad de la clase intanciada ' article.Numero = Convert.ToInt32(row.Cells("columnNumero").Value) article.Upc = Convert.ToString(row.Cells("columnUpc").Value) article.Descripcion = Convert.ToString(row.Cells("columnDescripcion").Value) article.Piezas = Convert.ToDecimal(row.Cells("columnPiezas").Value) article.Precio = Convert.ToDecimal(row.Cells("columnPrecio").Value) article.Importe = Convert.ToDecimal(row.Cells("columnImporte").Value) ' 'Vamos agregando el Item a la lista del detalle ' invoice.Detail.Add(article) Next ' 'Creamos una instancia del Formulario que contiene nuestro 'ReportViewer ' Dim frm As New FacturaRpt() ' 'Usamos las propiedades publicas del formulario, aqui es donde enviamos el valor 'que se mostrara en los parametros creados en el LocalReport, para este ejemplo 'estamos Seteando los valores directamente pero usted puede usar algun control ' frm.Titulo = "Este es un ejemplo de Factura" frm.Empresa = "Este es un ejemplo del Nombre de la Empresa" ' 'Recuerde que invoice es una Lista Generica declarada en FacturaRtp, es una lista 'porque el origen de datos del LocalReport unicamente permite ser enlazado a objetos que 'implementen IEnumerable. ' 'Usamos el metod Add porque Invoice es una lista e invoice es una entidad simple frm.Invoice.Add(invoice) ' 'Enviamos el detalle de la Factura, como Detail es una lista e invoide.Details tambien 'es un lista del tipo EArticulo bastara con igualarla '
frm.Detail = invoice.Detail frm.Show() End Sub Private Sub btnImprimir_Click(sender As System.Object, e As System.EventArgs) Handles btnImprimir.Click InvoiceGenerate() End Sub End Class Ahora solo queda probar nuestra aplicación: Llenamos los datos:
Presione el botón Imprimir, si siguió al pie de la letra el Articulo tendrá un reporte como este:
Observe, en el reporte el Formato numérico y Módena, al igual que no tenemos hojas de mas sin datos… Ahora, exporte el reporte a Pdf y observe que los márgenes están dentro del lim ite, sin generar hojas de mas, ni salirse de los márgenes:
Bueno, hemos llegado al final de este tutorial, en un entrega posterior abordaremos las imágenes en Reportes Locales y utilizaremos una Bd como fuente de datos para nuestro reporte. Saludos desde Monterrey, Nuevo León México!
Code Snippet Imports System Imports System.IO Imports System.Collections.Generic Imports System.ComponentModel Imports System.Data Imports System.Drawing Imports System.Text Imports System.Windows.Forms Imports System.Xml.Serialization Imports Microsoft.Reporting.WinForms Friend Class Form1 Private m_dataSet As DataSet Private m_rdl As MemoryStream Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load Dim m_dataSet As New DataSet m_dataSet.ReadXml("test.xml") DsToReport(m_dataSet, "ProductSales") End Sub Private Sub ShowReport(ByVal ds As DataSet, ByVal tabla As String) Me.ReportViewer1.Reset() Me.ReportViewer1.LocalReport.LoadReportDefinition(m_rdl) Me.ReportViewer1.LocalReport.DataSources.Add(New ReportDataSource("MyData", ds.Tables(tabla))) Me.ReportViewer1.RefreshReport() End Sub Private Function GenerateRdl(ByVal allFields As List(Of String)) As Me moryStream ', ByVal selectedFields As List(Of String)) As MemoryStream Dim ms As New MemoryStream() Dim gen As New DynamicTable.RdlGenerator() gen.AllFields = allFields gen.SelectedFields = allFields gen.WriteXml(ms) ms.Position = 0 Return ms End Function Private Sub DsToReport(ByVal ds As DataSet, ByVal tabla As String) Try Dim allFields As New List(Of String) Dim dataTable As DataTable = ds.Tables(tabla) Dim i As Integer For i = 0 To dataTable.Columns.Count - 1 allFields.Add(dataTable.Columns(i).ColumnName) Next i If Not (m_rdl Is Nothing) Then m_rdl.Dispose() End If m_rdl = GenerateRdl(allFields) ShowReport(ds, tabla) Catch ex As Exception MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Sub Private Sub OpenToolStripMenuItem_Click1(ByVal sender As Object, ByVal e As System.EventArgs) Handles OpenToolStripMenuItem.Click
If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then OpenDataFile(OpenFileDialog1.FileName, True) End If End Sub End Class
la función con la que interactuas es DsToReport igual queda a gusto y piachere de cada uno, yo le hice algunas modificaciones para que te sea más sencillo de entender. Saludos, Germán.
------------------------------------- ---------------------------------------- ----------------------------------Si la ayuda fué útil no olviden calificarla! =)
Codigo C# using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; using System.Configuration; using Microsoft.Reporting.WinForms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { SqlConnection sql = newSqlConnection(ConfigurationManager .ConnectionStrings["cnn"].ConnectionString); SqlDataAdapter da; SqlCommand cmd; Datos info; { public Form1() InitializeComponent(); da=new SqlDataAdapter (); info=new Datos(); } private void Form1_Load(object sender, EventArgs e){ } private void BBuscar_Click(object sender, EventArgs e){ using (sql){ sql.Open(); using (cmd = new SqlCommand()){ cmd.Connection = sql; if (string.IsNullOrEmpty(textBox1.Text)){ cmd.CommandText = "select * from empleado"; }else{ cmd.CommandText = "select * from empleado where codigo=@codigo"; cmd.Parameters.AddWithValue("@codigo", textBox1.Text);} da.SelectCommand = cmd; da.Fill(info, "empleado");}} this.reportViewer1.ProcessingMode = ProcessingMode.Local; this.reportViewer1.LocalReport.ReportEmbeddedResource =@"WindowsFormsApplication1.Report1.rdlc"; ReportDataSource rds = new ReportDataSource("Datos", info.Tables[0]); this.reportViewer1.LocalReport.DataSources.Clear(); this.reportViewer1.LocalReport.DataSources.Add(rds); this.reportViewer1.RefreshReport();}}}
y eso es todo ;)
ReportViewer con DataSet Tipado Que pasa si hacemos una aplicación para un vecino, una empresa pequeñísima o incluso un proyecto para la universidad y nos piden mostrar información en un reporte? pues fácil lo podemos hacer
super practico e incluso visualmente atractivo en Crystal Report asi: Reportes con Crystal Report . Pero y si se da el típico caso del profesor que te dice: "pues ustedes sabrán como lo hacen pero yo no voy a instalar nada mas que el Framework para Visual Studio" entonces toca que buscar una solución y esa es crear reportes locales a la aplicación, a lo mejor no sea tan buena comparando esta solución con usar Crystal Report pero el resultado termina siendo el mismo, entregar al usuario un reporte con la información que necesita y listo para imprimir. Vamos a hacer un reporte casero(local) para una aplicación de escritorio tanto en VB como en C#, la tabla que usaremos se llama empleado y tiene los siguientes campos:
Creamos un nuevo proyecto para escritorio y luego lo primero sera tener el Dataset y lo haremos desde la pestaña Data Sources en nuestro proyecto y seleccionamos agregar un nuevo Data Source al que llamaremos Datos con un DataTable llamado empleado, tal como se muestra:
listo, ya creamos un Dataset para nuestro reporte, ahora falta crear el reporte, para eso damos click derecho sobre nuestro proyecto en el Solution Explorer y agregamos un nuevo item que sera un reporte local y le dejamos como nombre Report1.rdlc(ten presente que el nombre que le des al reporte es muy importante para enlzar los datos) y lo guardamos en la misma carpeta de nuestro proyecto(igualmente la ubicacion de tu reporte es importante).
al hacer lo anterior tendremos una pantalla para diseñar nuestro reporte y en la parte izquierda una pestaña Toolbox desde la cual agregamos una tabla para nuestro ejemplo, tu puedes agregar una Matrix, Rectangle, List según lo necesites:
y al hacerlo se abrirá una ventana llamada Dataset Properties donde se nos pedirá definir una fuente de datos para poblar el reporte, aquí es donde usaremos el Dataset que creamos(aquel que
se llamaba Datos) y el Datatable respectivo, se llena así: Name: como nombre para nuestra fuente de datos para el reporte ponemos Datos. Data source: el Dataset que creamos desde Data Sources y cuyo nombre es Datos Avaible datasets: el nombre del Datatable del Dataset que creamos: empleado si tienes alguna duda regresate a ver la segunda imagen de este blog
Ahora en la parte izquierda tendremos una pestaña llamada Report Data y desde ahí jalamos los campos del Dataset hacia la tabla que agregamos en nuestro reporte así:
este es nuestro reporte, de lo mas sencillo, aquí solo muestro como poblar el reporte desde un Dataset, ustedes sabrán cual es el diseño que quieran aplicar
Lo ultimo sera regresar a nuestro formulario que el proyecto crea por defecto: Form1.vb le especificamos que reporte utilizar al ReportViewer desde el Choose Report y vamos a agregar desde el Toolbox los siguientes elementos un reportViewer asi como un label, un textbox y un botón a fin que quede como la imagen: