Printing is an essential feature for any Reporting tool. This stands for ActiveReports as well, which is hugely popular as a complete Reporting tool as it offers everything a report designer would require.

While Printing feature is concerned, a very frequently asked question from the customers is regarding the option to select the Paper Bin in the Printer. In this blog article, I am providing the implementation using the SystemPrinter Class which can be used to print a report from multiple bins available in a printer.

Before we go ahead with the implementation, I would like to put in some basic information about the history and importance of SystemPrinter class. Conventional ActiveReports printing is derived from standard .NET printing API. This means that when ActiveReports prints using Document.Print, a PrintDocument is sent to the standard .NET framework printing classes which communicate with the printer. However, if the installed printer drivers does not support .NET completely, then there could be some issues while printing.

To overcome such situations a new Class called SystemPrinter was introduced within ActiveReports. This is contained in the ActiveReports.Interop.dll assembly and interacts directly with the Printers. This assembly is available at “C:\Program Files\Common Files\GrapeCity\ActiveReports 6” on a machine which has ActiveReports 6 installed. Since this is a COM interop, it is not supported on 64 bit machines and therefore a 64 bit version ActiveReports.Interop64.dll was added later. This assembly can be found at “C:\Program Files\Common Files\GrapeCity\ActiveReports 6\redist” on your machine. Please note that either of these dll’s is required, to use the SystemPrinter class on basis of the target Operating System.

Now when we know the usage of SystemPrinter class, lets quickly understand the implementation to select the Paper Bin/Tray from the printer while printing. So to begin with, the first thing you need to do is to disable the default Print button and add custom Print button to handle the printing manually using the SystemPrinter Class.



Rpt rpt = new Rpt();
private void Form1_Load(object sender, EventArgs e)
{
//Remove the default printer button
this.viewer1.Toolbar.Tools.RemoveAt(2);
// Create and add the custom button
DataDynamics.ActiveReports.Toolbar.Button btn = new DataDynamics.ActiveReports.Toolbar.Button();
btn.Caption = "MyPrint";
btn.ToolTip = "Custom Print Button";
btn.ImageIndex = 1;
btn.ButtonStyle = DataDynamics.ActiveReports.Toolbar.ButtonStyle.TextAndIcon;
btn.Id = 333;
this.viewer1.Toolbar.Tools.Insert(2, btn);
viewer1.ToolClick += new DataDynamics.ActiveReports.Toolbar.ToolClickEventHandler(viewer1_ToolClick);

viewer1.Document = rpt.Document;
rpt.Run();
}

void viewer1_ToolClick(object sender, DataDynamics.ActiveReports.Toolbar.ToolClickEventArgs e)
{
// Capture the new tool's click to show the dialog
if (e.Tool.Id == 333)
{
arScale();
}
}


In the above code snippet, you would notice that in the Viewer_ToolClick event, the arScale function has been called which further makes a call to the SystemPrinter Class. The most important method is the StartJob() method which actually starts the print job. Similarly the EndJob() method marks the end. The SystemPrinter finishes the job, page by page so that you can set individual print settings for each page which is useful for the current scenario where report pages are printed from multiple printer trays. In this case, you need to define the PaperSource for the report pages accordingly. This blog sample implements two report pages which are printed from different trays in the same printer. Lets see the sample code:


private DataDynamics.ActiveReports.Document.Page aPage;
private void arScale()
{
aPage = new DataDynamics.ActiveReports.Document.Page();
DataDynamics.ActiveReports.Interop.SystemPrinter m_myARPrinter = new DataDynamics.ActiveReports.Interop.SystemPrinter();
m_myARPrinter.StartJob("Your Printer Name Goes Here");

System.Drawing.RectangleF rcPage = new RectangleF();

int nCount = rpt.Document.Pages.Count;

for (int i = 0; i < nCount; i++)
{
m_myARPrinter.StartPage();
aPage = rpt.Document.Pages[i];
if(i == 0)
{
//If this is the first page, we want a different page size and paper source
m_myARPrinter.PaperSource = m_myARPrinter.PrinterSettings.PaperSources[3];
m_myARPrinter.PaperSize = m_myARPrinter.PaperSizes[0];
m_myARPrinter.Graphics.PageUnit = System.Drawing.GraphicsUnit.Pixel;
rcPage.Width = aPage.Width;
rcPage.Height = aPage.Height;
}
else
{
m_myARPrinter.PaperSource = m_myARPrinter.PrinterSettings.PaperSources[0];
m_myARPrinter.PaperSize = m_myARPrinter.PaperSizes[2];
m_myARPrinter.Graphics.PageUnit = System.Drawing.GraphicsUnit.Pixel;
rcPage.Width = aPage.Width;
rcPage.Height = aPage.Height;
}

aPage.Draw(m_myARPrinter.Graphics, rcPage);
m_myARPrinter.EndPage();
}

m_myARPrinter.EndJob();
}


So the implementation is pretty simple and of course helpful in many situations. You can download the complete sample for your reference.
Download C# Sample
Download VB.Net Sample