Printing without the ReportViewer

In a Win Forms app, is it possible to print a report without using the ReportViewer control I want to provide a print button on a Form (like Outlook does) and then use an embedded Report to print the data so I don't really need the ReportViewer.

I would want to display the PrinterDialog though and use the settings from here to control the printed Report. Is this possible too

Regards

Graham



Answer this question

Printing without the ReportViewer

  • Debbio

    Will this printing method work in the June CTP of Visual Studio 2005

    Thanks.

       - Bob


  • Craig Demyanovich

    Besides changing the pagewidth and pageheight in the DeviceInfo section, what else needs to be done to print Landscape.
  • gloira

    I figured out the print quality issue. The sample code in this post uses the drawimage improperly. The code sample on the MSDN docs shows the correct usage:

    http://msdn2.microsoft.com/en-us/library/ms252091.aspx

    the PrintPage method should call DrawImage with the PrintPageEventArgs PageBounds property like this:

    ev.Graphics.DrawImage(pageImage, ev.PageBounds);

    The code sample in this post uses

    ev.Graphics.DrawImage(pageImage, 0, 0);

    which seems to cause the renderer to produce a rasterized EMF output.

    Another cool trick is to avoid writing out the .emf files like all the samples do, and juse use a MemoryStream instead.

    swap out the CreateStrem function with this:

    private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek)
    {
    Stream stream = new MemoryStream();
    m_streams.Add(stream);
    return stream;
    }




  • stej

    I am able to print; however, the report is being cut off on the right of the page. If I change the page width in the DeviceInfo section to be smaller then 8.5" it will display the cut off section on a second page. A width greater then 8.5" will cut off an inch or more as the width is made larger. A width of 8.5" also removes the right margin and I do not get a second page with the missing section of the report. This report was converted from an rdl to rdlc and would print correctly using the print control on the toolbar. Has anyone else experienced this issue

    Thanks


  • RenjithC

    In the final product you'll be able to print using the code below. Notice that ReportViewer object is not required. (This code will not work in Beta 2 unfortunately.)

    using System;
    using System.IO;
    using System.Data;
    using System.Text;
    using System.Drawing.Imaging;
    using System.Drawing.Printing;
    using System.Collections.Generic;
    using Microsoft.Reporting.WinForms;

    public class Demo : IDisposable
    {
        private int m_currentPageIndex;
        private IList<Stream> m_streams;
        private DataTable LoadSalesData()
        {
            DataSet dataSet = new DataSet();
            dataSet.ReadXml("data.xml");
            return dataSet.Tables[0];
        }
        private Stream CreateStream(string name, string fileNameExtension, Encoding encoding,
                                  string mimeType, bool willSeek)
        {
            Stream stream = new FileStream(name + "." + fileNameExtension, FileMode.Create);
            m_streams.Add(stream);
            return stream;
        }
        private void Export(LocalReport report)
        {
            string deviceInfo =
              "<DeviceInfo>" +
              "  <OutputFormat>EMF</OutputFormat>" +
              "  <PageWidth>8.5in</PageWidth>" +
              "  <PageHeight>11in</PageHeight>" +
              "  <MarginTop>0.25in</MarginTop>" +
              "  <MarginLeft>0.25in</MarginLeft>" +
              "  <MarginRight>0.25in</MarginRight>" +
              "  <MarginBottom>0.25in</MarginBottom>" +
              "</DeviceInfo>";
            Warning[] warnings;
            m_streams = new List<Stream>();
            report.Render("Image", deviceInfo, CreateStream, out warnings);
            foreach (Stream stream in m_streams)
                stream.Position = 0;
        }
        private void PrintPage(object sender, PrintPageEventArgs ev)
        {
            Metafile pageImage = new Metafile(m_streams[m_currentPageIndex]);
            ev.Graphics.DrawImage(pageImage, 0, 0);
            m_currentPageIndex++;
            ev.HasMorePages = (m_currentPageIndex < m_streams.Count);
        }
        private void Print()
        {
            const string printerName = "Microsoft Office Document Image Writer";
            if (m_streams == null || m_streams.Count == 0)
                return;
            PrintDocument printDoc = new PrintDocument(); 
            printDoc.PrinterSettings.PrinterName = printerName;
            if (!printDoc.PrinterSettings.IsValid)
            {
                string msg = String.Format("Can't find printer \"{0}\".", printerName);
                Console.WriteLine(msg);
                return;
            }
            printDoc.PrintPage += new PrintPageEventHandler(PrintPage);
            printDoc.Print();
        }
        private void Run()
        {
            LocalReport report = new LocalReport();
            report.ReportPath = "Report.rdlc";
            report.DataSources.Add(new ReportDataSource("Sales", LoadSalesData()));
            Export(report);
            m_currentPageIndex = 0;
            Print();
        }
        public void Dispose()
        {
            if (m_streams != null)
            {
                foreach (Stream stream in m_streams)
                    stream.Close();
            }
        }
        public static void Main(string[] args) 
        {
            using (Demo demo = new Demo())
            {
                demo.Run();
            }

        }
    }

     


  • Nilesh Rade

    3x for your reply. I don't know what the actual hardcopy print is. The problem I met with is similar to the one raised in the following URL :
    http://www.dotnet247.com/247reference/msgs/34/172114.aspx.

    My English is poor, so pls refer to the above URL and give me help. 3X!



  • zhili

    Well done! However, when I print the report, it zooms in. Isn't it strange 3x

  • Amadeus156553

    Are you seeing the zoom in the viewer or on the actual hardcopy print

  • Iwin

    I run in to the following error, "An error occurred during local report processing."

    The only changes that I made to the code sample given above was the Run method. I'm passing in an existing datatable and I'm setting the report as shown below. The try/catch is where the error is raised. In particular it's on the following line of code in the "Export(LocalReport report) method:

    report.Render("Image", deviceInfo, CreateStream, out warnings);

    public void Run(DataTable dt)

    {

    LocalReport report = new LocalReport();

    report.DataSources.Add(new ReportDataSource("MyReport", dt));

    report.ReportEmbeddedResource = "WindowsApplication5.Reports.ChangedFilesReport.rdlc";

    try

    {

    Export(report);

    }

    catch (Exception exc)

    {

    System.Windows.Forms.MessageBox.Show(exc.Message);

    }

    m_currentPageIndex = 0;

    Print();

    }

    Any ideas as to how to resolve this

    Thanks all in advance.


  • PinkFloyd11

    Well, I'm so close yet so far.

    I have found the GetPrintDocument method  on the Viewer and I thought I could do something like:

    All in code...
    1. Create a ReportView Control.
    2. Set the LocalReport properties for the report datasource and resource
    3. Create a PrintDialog control.
    4. Set the printDialog.Document property to reportView.GetPrintDocument()
    5. Show the PrintDialog
    6. Call printDialog.Document.Print()

    the problem I have is the following exception when I call GetPrintDocument():

    TEMPORARY RESTRICTION: Must be in print preview mode in local mode with rendering complete

    Can anyone tell me when or if the restriction will be lifted

    Graham

  • wjxia

    Has anyone noticed that when rendering using EMF manually the print quality is horrible   It appears to me that the internal report rendering used in the ReportViewer produces nice vector based EMF, whereas when using the referenced method to render without the ReportViewer control, the EMF output is very jagged like a raster image!



  • SSN757

    I tried sample in beta2, it didn't compile because function doesn't match delegate. Only added last parameter as below..

    private
    Stream CreateStream( string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek, Microsoft.ReportingServices.Interfaces.StreamOper oper )

    It's working fine.

    Thx for sample, it was only sample I could find Smile



  • Ahmed hussain

    Wow, thanks Rajeev. It does look quite complicated but it does seem to fit in to the printing framework quiet well.

    Graham


  • Tom in the gong

    'For those who want it in VB

    Option Strict On

    Option Explicit On

    Imports System

    Imports System.IO

    Imports System.Data

    Imports System.Text

    Imports System.Drawing.Imaging

    Imports System.Drawing.Printing

    Imports System.Collections.Generic

    Imports Microsoft.Reporting.WinForms

    Public Class Demo_DirectPrinting

    Implements IDisposable

    #Region " IDisposable "

    Private disposedValue As Boolean = False ' To detect redundant calls

    ' IDisposable

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)

    If Not Me.disposedValue Then

    If disposing Then

    ' TODO: free unmanaged resources when explicitly called

    If Not (m_streams Is Nothing) Then

    Dim stream As Stream

    For Each stream In m_streams

    stream.Close()

    Next stream

    End If

    End If

    ' TODO: free shared unmanaged resources

    End If

    Me.disposedValue = True

    End Sub

    ' This code added by Visual Basic to correctly implement the disposable pattern.

    Public Sub Dispose() Implements IDisposable.Dispose

    ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.

    Dispose(True)

    GC.SuppressFinalize(Me)

    End Sub

    #End Region

    Private m_currentPageIndex As Integer

    Private m_streams As IList(Of Stream)

    Private Function LoadSalesData() As DataTable

    Dim dataSet As New DataSet()

    dataSet.ReadXml("data.xml")

    Return dataSet.Tables(0)

    End Function

    'Private Function CreateStream(ByVal name As String, ByVal fileNameExtension As String, ByVal encoding As Encoding, ByVal mimeType As String, ByVal willSeek As Boolean, ByVal oper As Microsoft.ReportingServices.Interfaces.StreamOper) As Stream

    Private Function CreateStream(ByVal name As String, ByVal fileNameExtension As String, ByVal encoding As Encoding, ByVal mimeType As String, ByVal willSeek As Boolean) As Stream

    Dim rc As Stream = New FileStream(name + "." + fileNameExtension, FileMode.Create)

    m_streams.Add(rc)

    Return rc

    End Function

    Private Sub Export(ByVal report As LocalReport)

    Dim deviceInfo As String = _

    "<DeviceInfo>" + _

    " <OutputFormat>EMF</OutputFormat>" + _

    " <PageWidth>8.5in</PageWidth>" + _

    " <PageHeight>11in</PageHeight>" + _

    " <MarginTop>0.25in</MarginTop>" + _

    " <MarginLeft>0.25in</MarginLeft>" + _

    " <MarginRight>0.25in</MarginRight>" + _

    " <MarginBottom>0.25in</MarginBottom>" + _

    "</DeviceInfo>"

    Dim warnings() As Warning = Nothing

    m_streams = New List(Of Stream)

    report.Render("Image", deviceInfo, AddressOf CreateStream, warnings)

    Dim stream As Stream

    For Each stream In m_streams

    stream.Position = 0

    Next stream

    End Sub

    Private Sub PrintPage(ByVal sender As Object, ByVal ev As PrintPageEventArgs)

    Dim pageImage As New Metafile(m_streams(m_currentPageIndex))

    ev.Graphics.DrawImage(pageImage, 0, 0)

    m_currentPageIndex += 1

    ev.HasMorePages = m_currentPageIndex < m_streams.Count

    End Sub

    Private Sub Print()

    Const printerName As String = "Microsoft Office Document Image Writer"

    If m_streams Is Nothing Or m_streams.Count = 0 Then

    Return

    End If

    Dim printDoc As New PrintDocument()

    printDoc.PrinterSettings.PrinterName = printerName

    If Not printDoc.PrinterSettings.IsValid Then

    Dim msg As String = [String].Format("Can't find printer ""{0}"".", printerName)

    Console.WriteLine(msg)

    Return

    End If

    AddHandler printDoc.PrintPage, AddressOf PrintPage

    printDoc.Print()

    End Sub

    Private Sub Run()

    Dim report As New LocalReport()

    report.ReportPath = "Report.rdlc"

    report.DataSources.Add(New ReportDataSource("Sales", LoadSalesData()))

    Export(report)

    m_currentPageIndex = 0

    Print()

    End Sub

    'Entry point which delegates to C-style main Private Function

    Public Overloads Shared Sub Main()

    Main(System.Environment.GetCommandLineArgs())

    End Sub

    Public Overloads Shared Sub Main(ByVal args() As String)

    Dim demo As New Demo_DirectPrinting()

    Try

    demo.Run()

    Finally

    demo.Dispose()

    End Try

    End Sub

    End Class

     


  • Printing without the ReportViewer