|
// Copyright (c) 2003, Michael Mayer
// See License.txt that should have been included with this source file.
// or see http://www.mag37.com/csharp/articles/Printing/
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Drawing.Printing;
namespace ReportPrinting
{
/// <summary>
/// ReportDocument extends from <see cref="System.Drawing.Printing.PrintDocument"/>
/// and is customized for printing reports from one or more tables of data.
/// </summary>
/// <remarks>
/// <para>
/// A ReportDocument is used just like <see cref="System.Drawing.Printing.PrintDocument"/>
/// when used with other printing framework classes, such as <see cref="System.Windows.Forms.PrintDialog"/>
/// or <see cref="System.Windows.Forms.PrintPreviewDialog"/>
/// </para>
/// <para>
/// A ReportDocument object is the top level container for all the
/// sections that make up the report. (This consists of a header, body, and footer.)
/// </para>
/// <para>
/// The ReportDocument's main job is printing, which occurs when the
/// Print() method is called of the base class. The Print() method
/// iterates through all the ReportSections making up the document, \
/// printing each one.
/// </para>
/// <para>
/// The strategy design pattern is employed for formatting the report.
/// An object implementing <see cref="ReportPrinting.IReportMaker"/>
/// may be associated with the ReportDocument. This IReportMaker
/// object is application specific and knows how to create a report
/// based on application state and user settings. This object would be
/// responsible for creating sections, associating DataViews,
/// and applying any required styles through use of the
/// <see cref="ReportPrinting.TextStyle"/> class. It will generally
/// use the <see cref="ReportPrinting.ReportBuilder"/> class to
/// assist with the complexity of building a report.
/// </para>
/// </remarks>
public class ReportDocument : System.Drawing.Printing.PrintDocument
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
/// <summary>
/// Default Constructor
/// </summary>
public ReportDocument()
{
// This call is required by the Windows.Forms Form Designer.
InitializeComponent();
this.resetAfterPrint = true;
ResetPens();
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
IReportMaker reportMaker;
float pageHeaderMaxHeight = 1F;
float pageFooterMaxHeight = 1F;
ReportSection pageHeader;
ReportSection pageFooter;
ReportSection body;
private int currentPage;
int totalPages;
//bool pagesWereCounted;
//bool countPages = true;
bool resetAfterPrint;
Pen normalPen;
Pen thinPen;
Pen thickPen;
#region "Properties"
/// <summary>
/// An object that will setup this report before printing.
/// (Strategy pattern).
/// </summary>
public IReportMaker ReportMaker
{
get { return this.reportMaker; }
set { this.reportMaker = value; }
}
/// <summary>
/// Used to define the size of the page header
/// The header will stop at or before this distance from the top margin of the page
/// </summary>
public float PageHeaderMaxHeight
{
get { return this.pageHeaderMaxHeight; }
set { this.pageHeaderMaxHeight = value; }
}
/// <summary>
/// Used to define the size of the page footer
/// The footer will start at this distance from the bottom margin of the page
/// </summary>
public float PageFooterMaxHeight
{
get { return this.pageFooterMaxHeight; }
set { this.pageFooterMaxHeight = value; }
}
/// <summary>
/// Returns the current page number
/// </summary>
/// <returns>Integer for the current page number</returns>
public int GetCurrentPage()
{
return currentPage;
}
/// <summary>
/// Gets the total number of pages in the document.
/// This is only becomes valid during the printing of
/// the first page.
/// </summary>
/// <returns>Total number of pages</returns>
public int TotalPages
{
get { return this.totalPages; }
}
/// <summary>
/// Gets or sets the flag
/// indicating all sections are cleared after printing.
/// This allows the next print of a different document to assume
/// a clear document, and releas memory.
/// </summary>
public bool ResetAfterPrint
{
get { return this.resetAfterPrint; }
set { this.resetAfterPrint = value; }
}
/// <summary>
/// The ReportSection responsible for printing the page header.
/// </summary>
public ReportSection PageHeader
{
get { return this.pageHeader; }
set { this.pageHeader = value; }
}
/// <summary>
/// The ReportSection reponsible for printing the page footer.
/// </summary>
public ReportSection PageFooter
{
get { return this.pageFooter; }
set { this.pageFooter = value; }
}
/// <summary>
/// The ReportSection responsible for printing the page body.
/// </summary>
public ReportSection Body
{
get { return this.body; }
set { this.body = value; }
}
/// <summary>
/// Gets the pen for normal styled lines
/// </summary>
public Pen NormalPen
{
get { return this.normalPen; }
}
/// <summary>
/// Gets the pen for thin lines
/// </summary>
public Pen ThinPen
{
get { return this.thinPen; }
}
/// <summary>
/// Gets the pen for thick lines
/// </summary>
public Pen ThickPen
{
get { return this.thickPen; }
}
#endregion
/// <summary>
/// Resets pens back to default values
/// </summary>
public void ResetPens()
{
normalPen = new Pen (Color.Black, 0.03f);
thinPen = new Pen (Color.Black, 0.01f);
thickPen = new Pen (Color.Black, 0.08f);
}
/// <summary>
/// Reset the row and page count before printing
/// </summary>
/// <param name="e"></param>
protected override void OnBeginPrint(System.Drawing.Printing.PrintEventArgs e)
{
//this.pagesWereCounted = false;
this.totalPages = 0;
reset();
}
void reset()
{
if (this.ReportMaker != null)
{
this.ReportMaker.MakeDocument(this);
}
this.currentPage = 0;
//this.bodyBeginPrintCalled = false;
}
/// <summary>
/// The actual method to print a page
/// </summary>
/// <param name="e">PrintPageEventArgs</param>
/// <param name="sizeOnly">Indicates that only sizing is done</param>
/// <returns>True if there are more pages</returns>
protected virtual bool PrintAPage (PrintPageEventArgs e, bool sizeOnly)
{
Graphics g = e.Graphics;
g.PageUnit = GraphicsUnit.Inch;
// Define page bounds
float leftMargin = e.MarginBounds.Left / 100F;
float rightMargin = e.MarginBounds.Right / 100F;
float topMargin = e.MarginBounds.Top / 100F;
float bottomMargin = e.MarginBounds.Bottom / 100F;
float width = e.MarginBounds.Width / 100F;
float height = e.MarginBounds.Height / 100F;
Bounds pageBounds = new Bounds(leftMargin, topMargin, rightMargin, bottomMargin);
// Header
if (this.PageHeader != null)
{
Bounds headerBounds = pageBounds;
if (this.PageHeaderMaxHeight > 0)
{
headerBounds.Limit.Y = headerBounds.Position.Y + this.PageHeaderMaxHeight;
}
this.PageHeader.Print(this, g, headerBounds);
pageBounds.Position.Y += this.PageHeader.Size.Height;
}
// Footer
if (this.PageFooter != null)
{
Bounds footerBounds = pageBounds;
if (this.PageFooterMaxHeight > 0)
{
footerBounds.Position.Y = footerBounds.Limit.Y - this.PageFooterMaxHeight;
}
this.PageFooter.CalcSize (this, g, footerBounds);
footerBounds = footerBounds.GetBounds (this.PageFooter.Size,
this.PageFooter.HorizontalAlignment, this.PageFooter.VerticalAlignment);
this.PageFooter.Print (this, g, footerBounds);
pageBounds.Limit.Y -= this.PageFooter.Size.Height;
}
// Body
if (this.Body != null)
{
this.Body.Print(this, g, pageBounds);
e.HasMorePages = this.Body.Continued;
}
else
{
e.HasMorePages = false;
}
return e.HasMorePages;
} // OnPrintPage
/// <summary>
/// Overrided OnPrintPage from PrintDocument.
/// This method, on first call, may count the pages.
/// Then it will simple call PrintAPage on every
/// call.
/// </summary>
/// <param name="e"></param>
protected override void OnPrintPage (PrintPageEventArgs e)
{
// if (this.countPages && !this.pagesWereCounted)
// {
// this.totalPages = 0;
// while (PrintAPage(e, true))
// {
// this.totalPages++;
// }
// this.pagesWereCounted = true;
// }
// this.reset();
this.currentPage++; // preincrement, so the first page is page 1
PrintAPage(e, false);
}
/// <summary>
/// Called at the end of printing. If ResetAfterPrint is set (default is true)
/// then all text sections will be released after printing.
/// </summary>
/// <param name="e"></param>
protected override void OnEndPrint(System.Drawing.Printing.PrintEventArgs e)
{
if (this.ResetAfterPrint)
{
// reset stuff
this.PageHeader = null;
this.PageFooter = null;
this.Body = null;
this.PageHeaderMaxHeight = 0F;
this.PageFooterMaxHeight = 0F;
}
}
} // class
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.