Ho conosciuto la classe reportviewer quando ho sentito la necessità di dover mostrare a video i dati inseriti all’interno di una applicazione da me sviluppata.
Insieme allo studio di tale classe mi sono accostato a Sql Server Reporting Services, nella sua versione in locale (DataReport nel formato .rdlc) .
Una volta creato un template, aggiungendo al progetto un nuovo elemento di tipo “report”,
creavo un nuovo modulo/pagina AnteprimaStampa e trascinavo al suo interno il componente report “ReportViewer”, in modo tale che da codice potevo instanziare un oggetto della classe AnteprimaStampa e potevo impostare le property del suo reportviewer per poi tramite il metodo showDialog visualizzare il tutto a video.
In questi giorni, però, mi è stato posta una domanda particolare…E se volessi creare un pdf senza visualizzare l’anteprima??? E se volessi, inoltre, stamparlo senza dover utilizzare i pulsanti presenti nella schermata del reportviewer????
Subito ho pensato : “Potrei usare itextSharp, includere la dll al mio progetto e risolvere almeno il problema della creazione del pdf”
Qualcuno mi suggeriva di utilizzare il mailmerge con word, cioè creare un template in word e legarlo tramite questo metodo ai dati presenti sulla mia pagina/modulo, però questa soluzione risultava troppo dispendiosa (almeno con pagine aspx), in quanto richiedeva la creazione di un file xml per la sistemazione dei dati da passare al template, i dati dovevano essere trasferiti ad un file xls per poter ottenere l’origine dati da associare al file word.
Dopo un po… ecco il lampo di genio: “E se usassi DataReport ugualmente????? Ci sarà il modo per raggiungere il mio obiettivo con questa tecnologia”
E di fatti ecco a voi il codice per fare ciò che m’era stato chiesto.
Per prima cosa devo importare nella mia webForm/wimdowsForm ciò che segue:
Imports System.IO
Imports System.Text
Imports System.Drawing.Imaging
Imports System.Drawing.Printing
Imports Microsoft.Reporting.WinForms
poi dichiariamo queste variabili globali
Private path As String
Private nomeFile As String
Private warnings As Warning()
Private m_stream As IList(Of Stream)
Private WithEvents printDocument As PrintDocument
Private m_currentPageIndex As Integer
Private fileImmagine As String
E poi
metodi per la creazione del file pdf
''' <summary>
''' Esportazione di un reportviewer in un file pdf
''' </summary>
Private Sub ExportPDF()
Dim warning As Warning() = Nothing
Dim streamids As String()
Dim mimeType As String
Dim encoding As String
Dim extesion As String
Try
'istanzio un ogetto della classe Anteprima di stampa che contiene il ReportViewer
Dim anteprimaStampa As New AnteprimaStampa
With anteprimaStampa
'definisco le property del local report e gli assegno i valori da inserire nel datSource o nei parametri
.ReportViewer.LocalReport.ReportPath = Application.StartupPath & "\Report.rdlc"
.ReportViewer.LocalReport.DataSources.Add(New ReportDataSource("NomeDatasourceReport", MioDatasource))
'renderizzo il report senza mostrare l'anteprima
.ReportViewer.RefreshReport()
'renderizzo il report creato in formato pdf in un array di byte (sostituire “PDF” con “Excel” per ottenere la creazione di un file .xls, ovviamente rinominare il file \nomefile.xls)
Dim bytes As Byte() = .ReportViewer.LocalReport.Render("PDF", Nothing, mimeType, encoding, extesion, streamids, warning)
path = Application.StartupPath
nomeFile = "\nomeFile.pdf"
'istanzio un file stream, creo il file "path + nomeFile" e gli scrivo all'interno tutti byte generati dal render precedente
Dim fs As New FileStream(Application.StartupPath & nomeFile, FileMode.Create)
fs.Write(bytes, 0, bytes.Length)
'forzo la scrittura
fs.Flush()
'chiudo il fileStream
fs.Close()
'lancio il processo di stampa
GeneraFileImmaginePerStampa(.ReportViewer.LocalReport)
End With
Catch ex As Exception
“…….”
End Try
End Sub
metodi per la stampa del report generato
''' <summary>
''' Preparazione del report viewer alla stampa, creazione di un file image
''' </summary>
Private Sub GeneraFileImmaginePerStampa(ByVal report As LocalReport)
Try
'definisco un layout della pagina con i margini ed il formato di output del file che in seguito genererò
Dim deviceInfo As String = "<DeviceInfo>" + " <OutputFormat>EMF</OutputFormat>" + " <PageWidth>8.5in</PageWidth>"
deviceInfo += " <PageHeight>11in</PageHeight>" + " <MarginTop>0.25in</MarginTop>" + " <MarginLeft>1cm</MarginLeft>"
deviceInfo +=+" <MarginRight>1cm</MarginRight>" + " <MarginBottom>0.25in</MarginBottom>" + "</DeviceInfo>"
'istanzio una lista di Stream
m_streams = New List(Of (Stream)
'il report in formato immagine lo renderizzo nel file che viene creato nel metodo CreateStream passato cm parametro al metodo render
report.Render("Image", deviceInfo, AddressOf CreaStreamImmagine, warnings)
'per ogni file che viene generato imposto il flusso corrente a 0
For Each stream As Stream In m_streams
stream.Position = 0
Next
'imposto l'index di pagina a 0
m_currentPageIndex = 0
'preparo la stampa dopodichè avvierò un processo di stampa
PreparaStampaImmagine()
'chiudo i file che ho creato
For Each stream As Stream In m_streams
stream.Close()
Next
Catch ex As Exception
“……”
End Try
End Sub
''' <summary>
''' funzione che genera uno stream per un file contenente immagini e lo inserisce nella lista di stream m_streams
''' </summary>
Private Function CreaStreamImmagine(ByVal name As String, ByVal fileNameExtension As String, ByVal encoding As Encoding, ByVal mimeType As String, ByVal willSeek As Boolean) As Stream
Try
'instanzio un oggetto di tipo Stream con il nome del report, il file è l'immagine da stampare e ha estenzion .emf
Dim stream As Stream = New FileStream(name + "." + fileNameExtension, FileMode.Create)
'salvataggio del path del file di immagine, in modo da cancellarlo a fine operazione di stampa
fileImmagine = path + "\" + name + "." + fileNameExtension
'inserimento nella lista di Stream del file di immagine
m_streams.Add(stream)
Return stream
Catch ex As Exception
throw ex
End Try
End Function
''' <summary>
''' metodo per la preparazione alla stampa
''' </summary>
Private Sub PreparaStampaImmagine()
Dim msg As String
Dim printDoc As PrintDocument()
Try
'Se la lista di Stream non è instanziata o non ci sono file al suo interno visualizza un errore di stampa
If IsNothing(m_streams) Or m_streams.Count = 0 Then
msg = String.Format("File non trovato")
Debug.WriteLine(msg)
Exit Sub
End If
printDoc = New PrintDocument()
'Se le impostazioni di stampa non sono valide (es. non viene trovata la stampante predefinita) manda un messaggio di errore
If Not printDoc.PrinterSettings.IsValid Then
msg = String.Format("Errore nella stampa")
Debug.WriteLine(msg)
Exit Sub
End If
'Associo all'evento "PrintPage" dell'oggetto PrintDoc il metodo StampaPagina
AddHandler printDoc.PrintPage, AddressOf StampaPagina
'Scateno l'evento di stampa di printDoc, appena associato.
printDoc.Print()
'Cancello il file immagine che ho creato per la stampa.
IO.File.Delete(fileImmagine)
Catch ex As Exception
“……”
End Try
End Sub
''' <summary>
''' evento per la stampa di un documento
''' </summary>
Private Sub StampaPagina(ByVal sender As Object, ByVal e As PrintPageEventArgs)
Try
'generazione di un metafile grafico (sequenza di istruzioni grafiche da creare o visualizzare) con il file all'indice m_currentPageIndex
Dim pageImage As New Metafile(m_streams(m_currentPageIndex))
'disegna l'ogetto immagine, e.pagebounds da le dimensioni all'immagine.
e.Graphics.DrawImage(pageImage, e.PageBounds)
'incrementa il numero di pagina
m_currentPageIndex += 1
'controlla se c'è qualche altra cosa da stampare, se non c'è altro da stampare chiude il processo di stampa
e.HasMorePages = (m_currentPageIndex < m_streams.Count)
Catch ex As Exception
“……”
End Try
End Sub