Click here to Skip to main content
15,879,326 members
Articles / Multimedia / GDI+
Article

Printing a DataGridView on DotNet Framework

Rate me:
Please Sign up or sign in to vote.
4.71/5 (25 votes)
27 Apr 2008Eclipse6 min read 385.3K   126   120
This library provide DataGridView printing features on the FrameWork .NET 3.5. (C# VB F#)

GridDrawer.Net

Contents

Presentation

The DataGridView control is a very powerful tool to display data in tabular format. However, a printing method was not incorporated into the control which presents the developer to create or devise a method to easily print the contents of the DataGridView.

DataDrawer is a class DLL to easily provide DataGridView printing. The library is written in C# with a version for .NET 3.5 incorporating LINQ and a .NET 2.0 versions. The library supports the C++, C#, VB.NET, and F# development environments.

Demo GridDrawer.Net

Introduction

The Class Library DLL provides the developer with a seamless approach to achieve DataGridView printing.

The DLL implements the following features:
  • Print level by level or column by column
  • Print selected rows or columns
  • Center partitions on printed sheet
  • Page numbering
  • Optimized DataGridViewTextBoxCell printing
  • Word wrapping and cell size as presented in the DataGridView control
  • Implement the power of Framework .NET 3.5. A version for .NET 2.0 is also available.
  • Provide scale resizing to force columns to fit onto a single sheet
  • Optional Header, Footer and Title blocks printing
  • Self-contained library for developer ease of use
  • Compatible with C++, C#, VB.NET, and F#

Coding Line

To make the print job flow smoothly, one basic idea has been to create a Coding Line within the project:

The DataGridView has a number of Levels which are cut into Partitions. A Level identifies a number of rows which can be printed on a sheet. A Partition is the number of columns which can be printed on a sheet.

With this concept, it is very easy to make some calculations and having a set of partitions which cover the DataGridView.

Structure

Project Structure

Implementation

Class DataGridViewExtentions

DataGridViewExtentions Class

This class implements the print job, adds functionality to the DataGridView and its components.

The Font, ColumnWidth, HeaderHeight and RowHeight functions have some overloads which use a "scale" parameter. The “scale” parameter is the core of the "FitColumnsToPage" functionality.

The code was designed to provide a uniform or similar approach to the form of the Functions:

C#
public static Color ForeColor(this DataGridViewCell cell)
{
    if (cell.HasStyle && cell.Style.ForeColor != Color.Empty) return cell.Style.ForeColor;
    else return cell.InheritedStyle.ForeColor;
}

public static Color BackColor(this DataGridViewCell cell)
{
    if (cell.HasStyle && cell.Style.BackColor != Color.Empty) return cell.Style.BackColor;
    else return cell.InheritedStyle.BackColor;
}

Utilizing this approach to coding the functions should minimize initialize a style when it is not required. See Cell Styles in the Windows Forms DataGridView Control on MSDN

Class DocumentMetrics

DocumentMetrics Class

Usefull to keep track of the printable coordinates of a document;
in order to do that, the "FromPrintDocument" function builds a new PrintDocument based on the given PrintDocument parameters. This approach is used to decouple or separate the print properties from the library.

C#
public static DocumentMetrics FromPrintDocument(PrintDocument printDocument)
{
    PageSettings pageSettings = printDocument.DefaultPageSettings;
    
    return new DocumentMetrics()
    {
        Width = 
            (pageSettings.Landscape)
                ?pageSettings.PaperSize.Height:pageSettings.PaperSize.Width,
        Height = 
            (pageSettings.Landscape)
                ?pageSettings.PaperSize.Width:pageSettings.PaperSize.Height,
        LeftMargin = pageSettings.Margins.Left,
        TopMargin = pageSettings.Margins.Top,
        RightMargin = pageSettings.Margins.Right,
        BottomMargin = pageSettings.Margins.Bottom
    };
}

PartitionBounds Class

PartitionBounds Class

The PartitionBounds Class contains the bounds of the number of partitions that were split from the DataGridView, i.e., the included rows and columns of a partition as well as the coordinate information of the bounds (size). This class could have been named PartitionMetrics but there might be some confusion with DocumentMetrics.

Partition Class

Partition Class

The Patition class represents the portion of a DataGridView which can be printed on a single sheet.
This class encapsulate the PartitionBounds class and provides functions which give an easy way to retrieve the DataGridViewColumns and DataGridViewRows which are assigned to the partition which is to be printed.

C#
// code showing how rows are returned by this class
public DataGridViewRow GetRow(int i)
{
    return GridView.Rows[Bounds.StartRowIndex + i];
}

public IEnumerable<datagridviewrow /> GetRows()
{
    for (int i = 0; i < Bounds.RowsCount; i++)
        if (GetRow(i).Visible) yield return GetRow(i);
}

PrintBlock Abstract class

PrintBlock Abstract class

This class isolates the title, header, and footer printing from the library.
3-PrintBlock objects are defined in GridDrawer: TitlePrintBlock, SheetFooter, and SheetHeader.
These PrintBlock objects are defined by extending the PrintBlock class.

Described below is the approach to implement title, header, and footer printing with the library. You call the GetSize method first which sets a Rectangle in which the Draw method will print. This allows us to define some blocks to be printed without modifying the library core.

CodeEnum enumeration

The Draw function receives a Dictionary parameter containing information from the CodeEnum enumeration for the Page number, page count, date, and time.

Note. There is a reusable TitlePrintBlock class already implemented in Lib.GridDraw.Tools. See "Working with this library" section for more detail on how this works.

C#
public class TitlePrintBlock : PrintBlock
{
    public String Title { get; set; }
    public Color ForeColor { get; set; }
    public Font Font { get; set; }
    public StringFormat Format { get; set; }

    public override SizeF GetSize(Graphics g, DocumentMetrics metrics)
    {
        return g.MeasureString(Title, Font, metrics.PrintAbleWidth, Format);
    }

    public override void Draw(Graphics g, Dictionary<codeenum, /> codes)
    {
        g.DrawString(Title, Font, new SolidBrush(ForeColor), Rectangle, Format);
    }

}    

GridDrawer Class

The core of the library is the GridDrawer class. GridDrawer exposes the properties and methods of the class. Using this class should be straight forward and easily implemented into your code.

GridDrawer Class
There are three main axes in the class.

Calculate Partition bounds

  1. The first step when printing the document is to calculate partitions bounds of the sheet to be printed. Care must be taken for the Title (first level), Header, and Footer heights.
  2. Calculate the scale if "MustFitColumnsToPage" is set to true and the Columns width is greater than Sheet PrintAbleWidth.
  3. Define the rows which must appear in the first position of a partition.
  4. Define the columns which must appear in the first position of a partition.
  5. Define a code Dictionary which sets the PrintBlock abstract class for the title, header, and footer printing, page number, page count, date, and time information.

Create Partitions

All partitions are calculated and created in a single instance. Partitions are set from information calculated during the Initialization process or step.

Drawing a sheet

From the Partition information, the sheet is drawn.
  1. Header (optional)
  2. Title (optional)
  3. Partition (column header and cells of the partition)
  4. Footer (optional)

Working with the library

Needing a Header?

Create a class extending the PrintBlock class similar to the one included in the demo project.
C#
public class HeaderPrintBlock : PrintBlock
{
    float imgHeight = 75;


    public override SizeF GetSize(Graphics g, DocumentMetrics metrics)
    {
        return new SizeF(metrics.PrintAbleWidth, imgHeight + 2); //+2 for spacing with document
    }

    public override void Draw(System.Drawing.Graphics g, Dictionary<codeenum, /> codes)
    {
        GraphicsUnit units = GraphicsUnit.Pixel;
        RectangleF rec = Properties.Resources.logo.GetBounds(ref units);
        
        float scale = imgHeight / rec.Height;
        // as you can see below, we are using the base.Rectangle.property which has been set by GridDrawer Class
        // after it knows The Size of this block.
        g.DrawImage(Properties.Resources.logo, new RectangleF(Rectangle.X, Rectangle.Y, rec.Width * scale, imgHeight));
    }
}

Needing a Footer?

Create a class extending the PrintBlock class similar to the one included in the demo project.
C#
public class FooterPrintBlock : PrintBlock
{
    Font font = new Font("Tahoma", 9, GraphicsUnit.Point);

    public override SizeF GetSize(Graphics g, DocumentMetrics metrics)
    {
        return g.MeasureString("Page X Of Y", font);
    }


    public override void Draw(System.Drawing.Graphics g, Dictionary<codeenum, /> codes)
    {
        StringFormat format = new StringFormat();
        format.Trimming = StringTrimming.Word;
        format.FormatFlags = StringFormatFlags.NoWrap;
        format.Alignment = StringAlignment.Far;

        // as you can see below, we are using the codes param to know on which page we are for instance.
        g.DrawString(
            string.Format("Page {0} Of {1}", codes[CodeEnum.SheetNumber], codes[CodeEnum.SheetsCount]),
            font,
            new SolidBrush(Color.Black),
            Rectangle,
            format);
    }
}

Needing a title?

Initialize the reusable class implemented in Lib.GridDraw.Tools.TitlePrintBlock.cs.
C#
TitlePrintBlock titleBlock = new TitlePrintBlock(printDocument.DocumentName,Color.DarkBlue);

Last step: Print the DataGridView

The Lib.GridDraw.Tools.PrintingDataGridViewProvider class initializes the printProvider using the printDocument.PrintPage event to manage the printing of the DataGridview.
C#
printProvider = Tools.PrintingDataGridViewProvider.Create(
    printDocument,
    GridView, chkCenter.Checked, chkFitColumns.Checked,
    new TitlePrintBlock(printDocument.DocumentName,Color.DarkBlue),
    new PrintBlocks.HeaderPrintBlock(),
    new PrintBlocks.FooterPrintBlock());

TODO

Conlusion

I hope you enjoy GridDraw.NET. Do not hesitate providing your feedback. It has been a pleasure to create and contribute this project to the community.

Points of Interest

This is the first project I have written with .NET 3.5, using Linq. Understanding and using Linq simplified the source code.

Thanks

I whish to thank Salan Al-Ani for his CodeProject article
and to codeplex.com for providing source control feature for the GridDrawer Library.
I whish also to thank Marc Miller, he has reviewed whole parts of this article and corrected most of it grammar.

License

This article, along with any associated source code and files, is licensed under The Eclipse Public License 1.0


Written By
Other UMH
Belgium Belgium
* Bachelor of Information Management at ISAT Charleroi in Belgium.
* Master II of Information science at UMH Mons.

I spend my time in small projects which can help me or small enterprises and
I am very interested in designing projects
with specifications of UML or in applying usual design patterns.

Comments and Discussions

 
QuestionDataGridView printing on Windows 10 Pin
Member 390112029-Jan-17 11:19
Member 390112029-Jan-17 11:19 
QuestionPrinting Pin
Gines Bobby Babayran27-Sep-16 18:24
Gines Bobby Babayran27-Sep-16 18:24 
QuestionHelp me in Getting Header and Footer Pin
Member 121601808-Feb-16 4:57
Member 121601808-Feb-16 4:57 
Questionlimit the number of rows per page Pin
cahill29-Nov-15 4:52
cahill29-Nov-15 4:52 
Questionprinting datagridview Pin
Member 1172695728-May-15 20:40
Member 1172695728-May-15 20:40 
QuestionPrimary key Column/First Column Duplication in Partitions Pin
zameer_mfm24-Sep-14 1:51
zameer_mfm24-Sep-14 1:51 
QuestionPrint Grid With All Formatting Pin
Tsukasa8328-Aug-13 3:01
Tsukasa8328-Aug-13 3:01 
AnswerRe: Print Grid With All Formatting Pin
Member 110501451-Sep-14 1:31
Member 110501451-Sep-14 1:31 
Questionmultiple data grid Pin
dniona7-Jun-13 0:03
dniona7-Jun-13 0:03 
Question14 Error Pin
jml.nafis20-Jan-13 19:21
jml.nafis20-Jan-13 19:21 
QuestionFramework 2 Pin
Jhollman11-Aug-12 3:49
Jhollman11-Aug-12 3:49 
SuggestionCache the SolidBrush for speed up Pin
JWhattam21-Jun-12 17:36
JWhattam21-Jun-12 17:36 
QuestionHidden columns bug Pin
JWhattam20-Jun-12 18:26
JWhattam20-Jun-12 18:26 
AnswerRe: Hidden columns bug Pin
JWhattam24-Jun-12 15:03
JWhattam24-Jun-12 15:03 
QuestionGreat stuff Pin
Wrangly27-Mar-12 21:13
Wrangly27-Mar-12 21:13 
QuestionPrinting many grids Pin
nagham_4ng17-Nov-11 21:06
nagham_4ng17-Nov-11 21:06 
Questionright to left printing Pin
Member 227142422-Apr-11 3:52
Member 227142422-Apr-11 3:52 
AnswerRe: right to left printing Pin
BlaiseBraye25-Apr-11 20:08
BlaiseBraye25-Apr-11 20:08 
Generallast column is coming on nextpage problem... Pin
ashu218828-Mar-11 21:46
ashu218828-Mar-11 21:46 
GeneralRe: last column is coming on nextpage problem... Pin
BlaiseBraye25-Apr-11 20:11
BlaiseBraye25-Apr-11 20:11 
GeneralThere is no Microsoft.Jet.OLEDB.4.0 for 64 bit Pin
JoeSox10-Mar-11 9:25
JoeSox10-Mar-11 9:25 
GeneralRe: There is no Microsoft.Jet.OLEDB.4.0 for 64 bit Pin
BlaiseBraye25-Apr-11 20:12
BlaiseBraye25-Apr-11 20:12 
GeneralNothing to print if first column is invisible Pin
Dave Hary30-Oct-10 9:52
Dave Hary30-Oct-10 9:52 
GeneralRe: Nothing to print if first column is invisible Pin
ashu218821-Mar-11 0:26
ashu218821-Mar-11 0:26 
GeneralMy vote of 5 Pin
Resonate075-Oct-10 4:43
Resonate075-Oct-10 4:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.