Impresión de informes RDLC
[+] El principal problema que me encontré con el diseño de reportes con los informes rdlc de Visual Studio 2010, es que el control ReportViewer no cuenta con un método que envíe directamente el informe a imprimir
Si bien es cierto que puedes imprimir y exportar un informe mediante los comandos del propio ReportViewer, en muchas ocasiones y por requerimientos del proceso o del cliente es necesario la impresión directa del informe.
Navegando por internet y preguntando a San Google encontré una solución que resuelve el problema, de inicio la solución resulta un tanto confusa; en éste post no haré un análisis, ya que viéndolo trabajar puede uno ver su funcionamiento con claridad.
Así que… entremos en materia; el código y para no saturar el post dejo el link de la solución aquí. Personalmente le he hecho unas pequeñas modificación para crear una clase y que pudiera ser reusable, aquí lo dejo
1: public class ControladorImpresion : IDisposable
2: {
3:
4: #region Atributos
5:
6: private int m_currentPageIndex;
7: private IList<Stream> m_streams;
8:
9: #endregion
10:
11: #region Métodos privados
12:
13: private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
14: {
15: //Routine to provide to the report renderer, in order to save an image for each page of the report.
16: Stream stream = new FileStream(@"..\..\" + name + "." + fileNameExtension, FileMode.Create);
17: m_streams.Add(stream);
18: return stream;
19: }
20:
21: private void Export(LocalReport report)
22: {
23: //Export the given report as an EMF (Enhanced Metafile) file.
24: string deviceInfo =
25: "<DeviceInfo>" +
26: " <OutputFormat>EMF</OutputFormat>" +
27: " <PageWidth>8.5in</PageWidth>" +
28: " <PageHeight>11in</PageHeight>" +
29: " <MarginTop>0.25in</MarginTop>" +
30: " <MarginLeft>0.25in</MarginLeft>" +
31: " <MarginRight>0.25in</MarginRight>" +
32: " <MarginBottom>0.25in</MarginBottom>" +
33: "</DeviceInfo>";
34: Warning[] warnings;
35: m_streams = new List<Stream>();
36: report.Render("Image", deviceInfo, CreateStream, out warnings);
37: foreach (Stream stream in m_streams)
38: { stream.Position = 0; }
39: }
40:
41: private void PrintPage(object sender, PrintPageEventArgs ev)
42: {
43: //Handler for PrintPageEvents
44: Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
45: ev.Graphics.DrawImage(pageImage, ev.PageBounds);
46: m_currentPageIndex++;
47: ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
48: }
49:
50: private void Print()
51: {
52: //
53: PrintDocument printDoc;
54:
55: String printerName = ImpresoraPredeterminada();
56: if (m_streams == null || m_streams.Count == 0)
57: { return; }
58:
59: printDoc = new PrintDocument();
60: printDoc.PrinterSettings.PrinterName = printerName;
61: if (!printDoc.PrinterSettings.IsValid)
62: {
63: string msg = String.Format("Can't find printer \"{0}\".", printerName);
64: MessageBox.Show(msg, "Print Error");
65: return;
66: }
67: printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
68: printDoc.Print();
69: }
70:
71: private string ImpresoraPredeterminada()
72: {
73: //
74:
75: for(Int32 i = 0 ; i < PrinterSettings.InstalledPrinters.Count ; i++)
76: {
77: PrinterSettings a = new PrinterSettings();
78: a.PrinterName = PrinterSettings.InstalledPrinters[i].ToString();
79: if (a.IsDefaultPrinter)
80: { return PrinterSettings.InstalledPrinters[i].ToString(); }
81: }
82: return "";
83: }
84:
85: #endregion
86:
87: #region Métodos públicos
88:
89: public void Imprimir(LocalReport argReporte)
90: {
91: //
92: Export(argReporte);
93: m_currentPageIndex = 0;
94: Print();
95: }
96:
97: #endregion
98:
99: #region Soporte para implementación de interfaces
100:
101: #region IDisposable
102:
103: public void Dispose()
104: {
105: if (m_streams != null)
106: {
107: foreach (Stream stream in m_streams)
108: { stream.Close(); }
109: m_streams = null;
110: }
111: }
112:
113: #endregion
114:
115: #endregion
116:
117: }
Los cambios serían:
- Método público llamado Imprimir que recibe un parámetro del tipo LocalReport.
- Método privado llamado ImpresoraPredeterminada que busca la impresora predeterminada en la colección de impresoras instaladas regresando una cadena que representa el nombre de dicha impresora.
El uso de la clase sería:
1: ControladorImpresion objImpresion = new ControladorImpresion();
2: objImpresion.Imprimir(miReporteLoca);
Naturalmente el argumento miReporteLocal ya está creado, instanciado, con sus parámetros cargados y así con sus datos, independientemente de como se llene el informe, procuré que la clase tenga sólo la responsabilidad de imprimir el informe a la impresora predeterminada.
Hasta aquí dejo el post, espero les sea de utilidad y les permita ir temprano a casa…
Saludos…!
Perfecto. El código de la clase en VB seria:
ResponderEliminar(El codigo se transformó a vb automaticamente, añadí los imports y sustituí una linea de codigo:
AddHandler printDoc.PrintPage, New PrintPageEventHandler(AddressOf PrintPage)
'printDoc.PrintPage += New PrintPageEventHandler(AddressOf PrintPage)
Codigo:
Imports System
Imports System.IO
Imports Microsoft.Reporting.WebForms
Imports System.Drawing.Printing
Imports System.Drawing.Imaging
Public Class ControladorImpresion
Implements IDisposable
#Region "Atributos"
Private m_currentPageIndex As Integer
Private m_streams As IList(Of Stream)
#End Region
#Region "Métodos privados"
Private Function CreateStream(name As String, fileNameExtension As String, encoding As Encoding, mimeType As String, willSeek As Boolean) As Stream
'Routine to provide to the report renderer, in order to save an image for each page of the report.
Dim stream As Stream = New FileStream("..\..\" & name & "." & fileNameExtension, FileMode.Create)
m_streams.Add(stream)
Return stream
End Function
Private Sub Export(report As LocalReport)
'Export the given report as an EMF (Enhanced Metafile) file.
Dim deviceInfo As String = "" & " EMF" & " 8.5in" & " 11in" & " 0.25in" & " 0.25in" & " 0.25in" & " 0.25in" & ""
Dim warnings As Warning()
m_streams = New List(Of Stream)()
report.Render("Image", deviceInfo, AddressOf CreateStream, warnings)
For Each stream As Stream In m_streams
stream.Position = 0
Next
End Sub
Private Sub PrintPage(sender As Object, ev As PrintPageEventArgs)
'Handler for PrintPageEvents
Dim pageImage As New Metafile(m_streams(m_currentPageIndex))
ev.Graphics.DrawImage(pageImage, ev.PageBounds)
m_currentPageIndex += 1
ev.HasMorePages = (m_currentPageIndex < m_streams.Count)
End Sub
IMPORTANTE: Y ESTO TAMBIEN (no me lo metia en un sólo post)
ResponderEliminarPrivate Sub Print()
'
Dim printDoc As PrintDocument
Dim printerName As [String] = ImpresoraPredeterminada()
If m_streams Is Nothing OrElse m_streams.Count = 0 Then
Return
End If
printDoc = New PrintDocument()
printDoc.PrinterSettings.PrinterName = printerName
If Not printDoc.PrinterSettings.IsValid Then
Dim msg As String = [String].Format("Can't find printer ""{0}"".", printerName)
'MessageBox.Show(msg, "Print Error")
Throw New Exception("Error al imprimir en clase PRINTER")
Return
End If
AddHandler printDoc.PrintPage, New PrintPageEventHandler(AddressOf PrintPage)
'printDoc.PrintPage += New PrintPageEventHandler(AddressOf PrintPage)
printDoc.Print()
End Sub
Private Function ImpresoraPredeterminada() As String
'
For i As Int32 = 0 To PrinterSettings.InstalledPrinters.Count - 1
Dim a As New PrinterSettings()
a.PrinterName = PrinterSettings.InstalledPrinters(i).ToString()
If a.IsDefaultPrinter Then
Return PrinterSettings.InstalledPrinters(i).ToString()
End If
Next
Return ""
End Function
#End Region
#Region "Métodos públicos"
Public Sub Imprimir(argReporte As LocalReport)
'
Export(argReporte)
m_currentPageIndex = 0
Print()
End Sub
#End Region
#Region "Soporte para implementación de interfaces"
#Region "IDisposable"
Public Sub Dispose()
If m_streams IsNot Nothing Then
For Each stream As Stream In m_streams
stream.Close()
Next
m_streams = Nothing
End If
End Sub
#End Region
#End Region
Public Sub Dispose1() Implements IDisposable.Dispose
End Sub
End Class
Buenas les comento que logre hacer q imprima en impresoras normales pero en las de punto de venta sale todas las letras pegadas hacia la izquierda del recibo alguien sabrá como corregirlo
ResponderEliminarGracias
Muchas Gracias buscaba un codigo como este
ResponderEliminar