Search code examples
c#vb.netwinformsreportrdlc

VB.NET - Print RDLC Report without showing ReportViewer control


I managed to Create a DLL with the help of Reza Aghaei

Here is the C# code (that I get from Print RDLC Report without showing ReportViewer Control):

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

public static class LocalReportExtensions
{
    public static void Print(this LocalReport report)
    {
        var pageSettings = new PageSettings();
        pageSettings.PaperSize = report.GetDefaultPageSettings().PaperSize;
        pageSettings.Landscape = report.GetDefaultPageSettings().IsLandscape;
        pageSettings.Margins = report.GetDefaultPageSettings().Margins;
        Print(report, pageSettings);
    }

    public static void Print(this LocalReport report, PageSettings pageSettings)
    {
        string deviceInfo =
            $@"<DeviceInfo>
                <OutputFormat>EMF</OutputFormat>
                <PageWidth>{pageSettings.PaperSize.Width * 100}in</PageWidth>
                <PageHeight>{pageSettings.PaperSize.Height * 100}in</PageHeight>
                <MarginTop>{pageSettings.Margins.Top * 100}in</MarginTop>
                <MarginLeft>{pageSettings.Margins.Left * 100}in</MarginLeft>
                <MarginRight>{pageSettings.Margins.Right * 100}in</MarginRight>
                <MarginBottom>{pageSettings.Margins.Bottom * 100}in</MarginBottom>
            </DeviceInfo>";

        Warning[] warnings;
        var streams = new List<Stream>();
        var currentPageIndex = 0;

        report.Render("Image", deviceInfo, 
            (name, fileNameExtension, encoding, mimeType, willSeek) => 
            {
                var stream = new MemoryStream();
                streams.Add(stream);
                return stream;
            }, out warnings);

        foreach (Stream stream in streams)
            stream.Position = 0;

        if (streams == null || streams.Count == 0)
            throw new Exception("Error: no stream to print.");

        var printDocument = new PrintDocument();
        printDocument.DefaultPageSettings = pageSettings;
        if (!printDocument.PrinterSettings.IsValid)
            throw new Exception("Error: cannot find the default printer.");
        else
        {
            printDocument.PrintPage += (sender, e) =>
            {
                Metafile pageImage = new Metafile(streams[currentPageIndex]);
                Rectangle adjustedRect = new Rectangle(
                    e.PageBounds.Left - (int)e.PageSettings.HardMarginX,
                    e.PageBounds.Top - (int)e.PageSettings.HardMarginY,
                    e.PageBounds.Width,
                    e.PageBounds.Height);
                e.Graphics.FillRectangle(Brushes.White, adjustedRect);
                e.Graphics.DrawImage(pageImage, adjustedRect);
                currentPageIndex++;
                e.HasMorePages = (currentPageIndex < streams.Count);
                e.Graphics.DrawRectangle(Pens.Red, adjustedRect);
            };
            printDocument.EndPrint += (Sender, e) =>
            {
                if (streams != null)
                {
                    foreach (Stream stream in streams)
                        stream.Close();
                    streams = null;
                }
            };
            printDocument.Print();
        }
    }
}

In C# as mentioned by Reza Aghaei the function is called with

this.reportViewer1.LocalReport.Print();

I Reference and tried to call this in vb.net

if I try

this.reportViewer1.LocalReport.Print()

or

LocalReport.Print()

it gives error.

What am I missing Kindly Help or if an Expert can convert it in Vb.net that would be really appreciated.

My Receipt I made look like this.

enter image description here

I would appreciate if any expert help me solve this as I mainly work in VB.net.


Solution

  • Note: All the converters that I tried were unable to convert the C# code of the linked post to a correct VB.NET version. You can find the original C# version in the linked post: Print RDLC Report without showing ReportViewer Control.

    VB.NET - Print RDLC Report without showing ReportViewer control

    Here is the VB version of the Print extension method of LocalReport:

    Imports Microsoft.Reporting.WinForms
    Imports System.Drawing.Imaging
    Imports System.Drawing.Printing
    Imports System.IO
    Imports System.Runtime.CompilerServices
    
    Public Module LocalReportExtensions
        <Extension()>
        Sub Print(ByVal report As LocalReport)
            Dim pageSettings = New PageSettings()
            pageSettings.PaperSize = report.GetDefaultPageSettings().PaperSize
            pageSettings.Landscape = report.GetDefaultPageSettings().IsLandscape
            pageSettings.Margins = report.GetDefaultPageSettings().Margins
            Print(report, pageSettings)
        End Sub
    
        <Extension()>
        Sub Print(ByVal report As LocalReport, ByVal pageSettings As PageSettings)
            Dim deviceInfo As String = $"<DeviceInfo>
                    <OutputFormat>EMF</OutputFormat>
                    <PageWidth>{pageSettings.PaperSize.Width * 100}in</PageWidth>
                    <PageHeight>{pageSettings.PaperSize.Height * 100}in</PageHeight>
                    <MarginTop>{pageSettings.Margins.Top * 100}in</MarginTop>
                    <MarginLeft>{pageSettings.Margins.Left * 100}in</MarginLeft>
                    <MarginRight>{pageSettings.Margins.Right * 100}in</MarginRight>
                    <MarginBottom>{pageSettings.Margins.Bottom * 100}in</MarginBottom>
                </DeviceInfo>"
            Dim warnings() As Warning
            Dim streams = New List(Of Stream)()
            Dim currentPageIndex = 0
            report.Render("Image", deviceInfo,
                          Function(name, fileNameExtension, encoding, mimeType, willSeek)
                              Dim stream = New MemoryStream()
                              streams.Add(stream)
                              Return stream
                          End Function, warnings)
    
            For Each stream As Stream In streams
                stream.Position = 0
            Next
    
            If streams Is Nothing OrElse streams.Count = 0 Then
                Throw New Exception("Error: no stream to print.")
            End If
    
            Dim printDocument = New PrintDocument()
            printDocument.DefaultPageSettings = pageSettings
    
            If Not printDocument.PrinterSettings.IsValid Then
                Throw New Exception("Error: cannot find the default printer.")
            Else
                AddHandler printDocument.PrintPage,
                    Sub(sender, e)
                        Dim pageImage As Metafile = New Metafile(streams(currentPageIndex))
                        Dim adjustedRect As Rectangle = New Rectangle(
                            e.PageBounds.Left - CInt(e.PageSettings.HardMarginX),
                            e.PageBounds.Top - CInt(e.PageSettings.HardMarginY),
                            e.PageBounds.Width,
                            e.PageBounds.Height)
                        e.Graphics.FillRectangle(Brushes.White, adjustedRect)
                        e.Graphics.DrawImage(pageImage, adjustedRect)
                        currentPageIndex += 1
                        e.HasMorePages = (currentPageIndex < streams.Count)
                        e.Graphics.DrawRectangle(Pens.Red, adjustedRect)
                    End Sub
    
                AddHandler printDocument.EndPrint,
                    Sub(Sender, e)
                        If streams IsNot Nothing Then
                            For Each stream As Stream In streams
                                stream.Close()
                            Next
                            streams = Nothing
                        End If
                    End Sub
    
                printDocument.Print()
            End If
        End Sub
    End Module
    

    To use above code, it's enough to call Print extension method on a LocalReport. For example if you have a (visible or invisible ReportViewer):

    Me.ReportViewer1.LocalReport.Print()
    

    Of if you want to pass printer settings:

    Me.ReportViewer1.LocalReport.Print(ReportViewer1.GetPageSettings())