4

I was wondering if is possible to send/print data from DataGridView directly to rdlc report without binding it to ReportViewercontrol.

There are many threads about binding dgv data to report viewer control. I don't want to create another form with report viewer control, but use existing form with data on DataGridView and on print button to send the data to RDLC report and print it.

Is it possible?
Thanks

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
NavCore
  • 1,115
  • 3
  • 10
  • 25
  • [Walkthrough: Printing a Local Report without Preview](https://msdn.microsoft.com/en-us/library/ms252091.aspx) – Reza Aghaei Jan 11 '16 at 17:04
  • That is a document printing and not .rdlc. Thanks, but I don't need that! – NavCore Jan 11 '16 at 17:35
  • I need smth like this: http://stackoverflow.com/questions/3360326/how-to-create-crystal-report-using-datagridview-values-without-using-database-in, but without using report viewer control. Is it possible? – NavCore Jan 11 '16 at 17:36
  • 1
    It seems you didn't read the article and codes. *This walkthrough shows how to programmatically print a report without viewing it, using the LocalReport object and the CreateStreamCallback callback function.* – Reza Aghaei Jan 11 '16 at 17:38
  • Yes I read it few days ago. I tried with similar document printing by getting data from DataGridView and draw it using System.Drawing.Printing. But I had lot of problems to measure page content and go to next page. Then I gave up! But I don't know where the data.xml came from :( and how to generate it. I have lot of existing forms. Most of them are using DataGridView to present data. I would like to create *.rdlc report for each form. Then in my form on print button send the data from the grid directly to the report and print it! Is that possible? – NavCore Jan 11 '16 at 18:04
  • 1
    As another option you can set the `Visible`property of a `ReportViewer` control to `false` and then set it to load the report and when the report loaded completely (while the report viewer) is invisible, call `PrintDialog()` method of the report viewer. – Reza Aghaei Jan 11 '16 at 18:14
  • I edited the question and removed the answer from question. Since the question title and content and the answer is about RDLC reports, putting an answer about CrystalReports in question is somehow confusing. If for any reason you want to post the solution also for crystal reports, please add it as another answer :) – Reza Aghaei Oct 27 '16 at 15:20

1 Answers1

15

You can print an RDLC report programmatically by using LocalReport object and CreateStreamCallback callback function. Here is a complete Microsoft docs walkthrough which you may find useful:

To make it easier to use, I've created a Print extension method which you can easily use it this way:

this.reportViewer1.LocalReport.Print();

Here is the extension method:

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();
        }
    }
}

Print with showing Print dialog

Just in case someone wants to print with showing Print dialog, you can put a ReportViewer on form and set the Visible property of the control to false then pass data to the report and when the RenderingComplete event fired, call PrintDialog:

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • I've added invisible CrystalReportViewer to my form and called PrintReport() method that opens print dialog. That's what I need. Many thanks Reza!! – NavCore Jan 12 '16 at 12:26
  • Also future readers may find this post useful: [Loading .rdlc report in Reportviewer manually](http://stackoverflow.com/questions/40056855/loading-rdlc-report-in-reportviewer-manually) – Reza Aghaei Oct 27 '16 at 15:24
  • Thanks Reza. The invisible trick is really neat. The extension method on the other hand is something else altogether. – kuklei Oct 05 '18 at 18:28
  • This works great. Thanks! A window appears in taskbar for a second. Anyone know how can I avoid this? – Ignacio May 26 '19 at 22:12
  • I found a solution: just add printDocument.PrintController = new StandardPrintController(); before printDocument.Print(). – Ignacio May 26 '19 at 23:06
  • 1
    hey mr.Rezan , FoxLearn Stole from you this solution https://www.youtube.com/watch?v=uiTTgwoticY&t=152s – Tariq Hajeer Nov 16 '20 at 01:47