Click here to Skip to main content
15,886,579 members
Articles / Programming Languages / C#

XmlStore Part 2: Printing DataGridView Contents

Rate me:
Please Sign up or sign in to vote.
4.71/5 (7 votes)
18 Mar 2007CPOL7 min read 70K   3.4K   51  
A utility to read, edit, encrypt, decrypt, write and print XmlStore files
using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Data;
using System.Windows.Forms;
using System.Diagnostics;

// This module contains two classes
// #1:  'VVX.DGVPrinter': Adapted from "The DataGridViewPrinter Class", By Salan Al-Ani. 
//                        See http://www.codeproject.com/csharp/datagridviewprinter.asp 
// #2:  'VVX.Print': My own VVX.Print "wrapper"

namespace VVX
{
    #region DGVPrinter

    /// <summary>
    /// This is a renamed, refactored and slightly modified version of DataGridViewPrinter
    /// originally created by Salan Al-Ani and downloaded from CodeProject (around Mar 10,2007)
    /// </summary>
    class DGVPrinter
    {
        private string mNameOfClient = "Unknown";

        // The PrintDocument to be used for printing.
        PrintDocument mPrintDoc;
        PrintDialog mPrintDlg;
        Margins mPageMargins = new Margins(0, 0, 0, 0);
        Margins mCellMargins = new Margins(2, 2, 2, 2);

        private DataGridView mTheDataGridView; // The DataGridView Control which will be printed
        private PrintDocument mThePrintDocument; // The PrintDocument to be used for printing
        private bool mIsCenterOnPage; // Determine if the report will be printed in the Top-Center of the page

        private bool mIsWithTitle; // Determine if the page contain title text
        private string mTheTitleText; // The title text to be printed in each page (if IsWithTitle is set to true)
        private Font mTheTitleFont; // The font to be used with the title text (if IsWithTitle is set to true)
        private Color mTheTitleColor; // The color to be used with the title text (if IsWithTitle is set to true)

        private bool mIsWithPaging; // Determine if paging is used
        private bool mIsWithColHeaders = true; // Determines if header is printed
        private int mPageNumber; //was static

        private int mCurrentRow; // A static parameter that keep track on which Row (in the DataGridView control) that should be printed
        private float mCurrentY; // A parameter that keep track on the y coordinate of the page, so the next object to be printed will start from this y coordinate

        private int mPageWidth;
        private int mPageHeight;

        private float mColHeaderHeight;
        private List<float> mRowHeight;
        private List<float> mColumnWidthPadded;
        private float mTheDataGridViewWidth;
        private float mColumnWidthMin = 0.0f;   //in in 1/100th inches
        private float mColumnWidthMax = 300.0f;   //in in 1/100th inches

        // Maintain a generic list to hold start/stop points for the column printing
        // This will be used for wrapping in situations where the DataGridView will not fit on a single page
        private List<int[]> mColumnRange;
        private List<float> mColumnRangeWidth;
        private int mColumnRangeCur;

        //*****************************************************************************
        // Properties
        //*****************************************************************************
        /// <summary>
        /// This is used to set PrintDocument.Name (not the printed Title)
        /// </summary>
        public string NameOfClient
        {
            get { return mNameOfClient; }
            set { mNameOfClient = value; }
        }

        /// <summary>
        /// Max column width in inches
        /// </summary>
        public float ColumnWidthMax
        {
            get { return mColumnWidthMax/100f; }
            set { mColumnWidthMax = value*100f; }
        }

        /// <summary>
        /// Min column width in inches
        /// </summary>
        public float ColumnWidthMin
        {
            get { return mColumnWidthMin / 100f; }
            set { mColumnWidthMin = value * 100f; }
        }

        public Margins PageMargins
        {
            get { return mPageMargins; }
            set { mPageMargins = value; }
        }

        public string PageTitle
        {
            get { return mTheTitleText; }
            set { mTheTitleText = value; }
        }

        public Font PageTitleFont
        {
            get { return mTheTitleFont; }
            set { mTheTitleFont = value; }
        }

        public Color PageTitleColor
        {
            get { return mTheTitleColor; }
            set { mTheTitleColor = value; }
        }

        public Margins CellMargins
        {
            get { return mCellMargins; }
            set { mCellMargins = value; }
        }

        public bool ShowPageNumbers
        {
            get { return mIsWithPaging; }
            set { mIsWithPaging = value; }
        }

        public bool HorizontallyCenterOnPage
        {
            get { return mIsCenterOnPage; }
            set { mIsCenterOnPage = value; }
        }

        //*****************************************************************************
        // The class constructor
        //*****************************************************************************
        public DGVPrinter(DataGridView aDataGridView)
        {
            mTheDataGridView = aDataGridView;

            //bool mbCenterOnPage = true; //MsgBox.Confirm("Center on the page?");
            //bool mTitleShow = true;
            //string mTitleText = "Customers";
            //Font mTitleFont = new Font("Tahoma", 18, FontStyle.Bold, GraphicsUnit.Point);
            //Color mTitleColor = Color.Black;
            //bool mPagingEnabled = true;

            mIsCenterOnPage = true;
            mIsWithTitle = true;
            mTheTitleText = "Customers";
            mTheTitleFont = new Font("Tahoma", 12, FontStyle.Bold, GraphicsUnit.Point);
            mTheTitleColor = Color.Black;
            mIsWithPaging = true;

            DoInit();
        }

        public DGVPrinter(DataGridView aDataGridView
                                    , PrintDocument aPrintDocument
                                    , bool CenterOnPage
                                    , bool WithTitle
                                    , string aTitleText
                                    , Font aTitleFont
                                    , Color aTitleColor
                                    , bool WithPaging)
        {
            mTheDataGridView = aDataGridView;
            mThePrintDocument = aPrintDocument;
            mIsCenterOnPage = CenterOnPage;
            mIsWithTitle = WithTitle;
            mTheTitleText = aTitleText;
            mTheTitleFont = aTitleFont;
            mTheTitleColor = aTitleColor;
            mIsWithPaging = WithPaging;

            DoInit();
        }

        //*****************************************************************************
        // The class constructor helper
        //*****************************************************************************
        private void DoInit()
        {
            if (mPrintDoc == null)
            {
                this.mPrintDoc = new PrintDocument();
                this.mPrintDoc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.OnPrintPage);
            }
            mThePrintDocument = this.mPrintDoc;

            mPageNumber = 0;

            mRowHeight = new List<float>();
            mColumnWidthPadded = new List<float>();

            mColumnRange = new List<int[]>();
            mColumnRangeWidth = new List<float>();

            // Calculating the PageWidth and the PageHeight
            if (!mThePrintDocument.DefaultPageSettings.Landscape)
            {
                mPageWidth = mThePrintDocument.DefaultPageSettings.PaperSize.Width;
                mPageHeight = mThePrintDocument.DefaultPageSettings.PaperSize.Height;
            }
            else
            {
                mPageHeight = mThePrintDocument.DefaultPageSettings.PaperSize.Width;
                mPageWidth = mThePrintDocument.DefaultPageSettings.PaperSize.Height;
            }

            //--- Calculate the page margins
            //this.mPageMargins = mThePrintDocument.DefaultPageSettings.Margins;

            // Set current row to be printed is the first row in the DataGridView control
            mCurrentRow = 0;
        }

        //*****************************************************************************
        // The function that calculate the height of each row (including the header row), 
        // the width of each column (according to the longest text in all its cells 
        // including the header cell), and the whole DataGridView width
        //*****************************************************************************
        private void Calculate(Graphics g)
        {
            if (mPageNumber == 0) // Just calculate once
            {
                mColHeaderHeight = 0;

                mTheDataGridViewWidth = 0;

                //----------------------------------------------------------------
                // loop through all the COLUMNS
                //----------------------------------------------------------------
                bool bSaveRowHeight = true;

                for (int iCol = 0; iCol < mTheDataGridView.Columns.Count; iCol++)
                {
                    if (mTheDataGridView.Columns[iCol].Visible == false)
                        continue;

                    float colWidth = 0;

                    //----------------------------------------------------------------
                    // first do calc for the HEADER
                    //----------------------------------------------------------------
                    if(this.mIsWithColHeaders)
                    {
                        Font hdrFont;
                        SizeF hdrSize = new SizeF();
                        // get the header font
                        hdrFont = mTheDataGridView.ColumnHeadersDefaultCellStyle.Font;
                        if (hdrFont == null) // If there is no special HeaderFont style, then use the default DataGridView font style
                            hdrFont = mTheDataGridView.DefaultCellStyle.Font;

                        //--- get the header size
                        hdrSize = g.MeasureString(mTheDataGridView.Columns[iCol].HeaderText, hdrFont);

                        hdrSize.Width += this.mCellMargins.Left + this.mCellMargins.Right;
                        hdrSize.Height += this.mCellMargins.Top + this.mCellMargins.Bottom;
                        //--- the column should be at least as wide as the header (incl padding)
                        colWidth = hdrSize.Width;
                        if (mColHeaderHeight < hdrSize.Height)
                            mColHeaderHeight = hdrSize.Height;
                    }

                    //----------------------------------------------------------------
                    // then do calc for the ROWS
                    //----------------------------------------------------------------
                    //--- loop through all the ROWS in the current COLUMN
                    for (int jRow = 0; jRow < mTheDataGridView.Rows.Count; jRow++)
                    {
                        Font rowFont;
                        SizeF cellSize;// = new SizeF();

                        //--- get the CELL font
                        rowFont = mTheDataGridView.Rows[jRow].DefaultCellStyle.Font;
                        if (rowFont == null) // If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
                            rowFont = mTheDataGridView.DefaultCellStyle.Font;

                        //--- set the height of the row 
                        //    (for now, only use the first column)
                        if (bSaveRowHeight)
                        {
                            cellSize = g.MeasureString("Anything", rowFont);
                            float rowHt = cellSize.Height
                                        + this.mCellMargins.Top + this.mCellMargins.Bottom;
                            mRowHeight.Add(rowHt);
                        }

                        //--- set the width of the column
                        string cellValue = mTheDataGridView[iCol,jRow].EditedFormattedValue.ToString();
                        //cellValue = mTheDataGridView.Rows[jRow].Cells[iCol].EditedFormattedValue.ToString();
                        cellSize = g.MeasureString(cellValue, rowFont);
                        if (colWidth < cellSize.Width)
                            colWidth = cellSize.Width;
                    }
                    //--- now save the width of the column
                    //if (mTheDataGridView.Columns[iCol].Visible) 
                    //    mTheDataGridViewWidth += colWidth;

                    colWidth += this.mCellMargins.Left + this.mCellMargins.Right;

                    //--- test for min
                    if (colWidth < mColumnWidthMin && mColumnWidthMin > 0)
                        colWidth = mColumnWidthMin;

                    //--- test for max
                    if (mColumnWidthMax > 0)
                    {
                        if (colWidth > mColumnWidthMax)
                            colWidth = mColumnWidthMax;
                    }
                    else
                    {
                        float maxPrintableWidth = this.DoGetPrintableWidth()
                                                - this.mTheDataGridViewWidth - 1;
                        if (colWidth > maxPrintableWidth)
                            colWidth = maxPrintableWidth;
                    }

                    mTheDataGridViewWidth += colWidth;

                    mColumnWidthPadded.Add(colWidth);

                    if (mRowHeight.Count > 0)
                    {
                        // assuming all cells in row are same height
                        bSaveRowHeight = false; 
                    }
                }

                //----------------------------------------------------------------
                // Define the start/stop column points based on the page width 
                // and the DataGridView Width. We will use this to determine the 
                // columns which are drawn on each page and how wrapping will be handled
                // By default, the wrapping will occurr such that the maximum number 
                // of columns for a page will be determine
                //----------------------------------------------------------------
                int col;
                int colStart = 0;
                for (col = 0; col < mTheDataGridView.Columns.Count; col++)
                {
                    if (mTheDataGridView.Columns[col].Visible)
                    {
                        colStart = col;
                        break;
                    }
                }

                int colEnd = mTheDataGridView.Columns.Count;
                for (col = mTheDataGridView.Columns.Count - 1; col >= 0; col--)
                {
                    if (mTheDataGridView.Columns[col].Visible)
                    {
                        colEnd = col + 1;
                        break;
                    }
                }

                float pageWidthUsed = 0f;
                float pagePrintableWidth = this.DoGetPrintableWidth();

                for (col = 0; col < mTheDataGridView.Columns.Count; col++)
                {
                    if (mTheDataGridView.Columns[col].Visible)
                    {
                        pageWidthUsed += mColumnWidthPadded[col];
                        // If the width is bigger than the page area, 
                        // then define a new column print range
                        if (pageWidthUsed > pagePrintableWidth)
                        {
                            pageWidthUsed -= mColumnWidthPadded[col];
                            mColumnRange.Add(new int[] { colStart, colEnd });
                            mColumnRangeWidth.Add(pageWidthUsed);
                            colStart = col;
                            pageWidthUsed = mColumnWidthPadded[col];
                        }
                    }
                    // Our end point is actually one index above the current index
                    colEnd = col + 1;
                }

                // Add the last set of columns
                mColumnRange.Add(new int[] { colStart, colEnd });
                mColumnRangeWidth.Add(pageWidthUsed);
                mColumnRangeCur = 0;
            }

#if !true
            {
                int n;
                string sMsg = "";
                for (n = 0; n < this.mColumnRangeWidth.Count; n++)
                {
                    sMsg = String.Format("n={0}\t Width={1}", n, this.mColumnRangeWidth[n]);
                    Debug.WriteLine(sMsg);
                }
                for (n = 0; n < this.mColumnWidthPadded.Count; n++)
                {
                    sMsg = String.Format("n={0}\t Width={1}", n, this.mColumnWidthPadded[n]);
                    Debug.WriteLine(sMsg);
                }
            }
#endif
        }

        //*****************************************************************************
        // Helper function
        //*****************************************************************************
        private int DoGetPrintableWidth()
        {
            int pagePrintWidth = this.mPageWidth 
                               - this.mPageMargins.Left 
                               - this.mPageMargins.Right;
            return pagePrintWidth;
        }

        //*****************************************************************************
        // Helper function
        //*****************************************************************************
        private int DoGetPrintableHeight()
        {
            int pagePrintHeight = this.mPageHeight 
                                - this.mPageMargins.Top 
                                - this.mPageMargins.Bottom;
            return pagePrintHeight;
        }

        //*****************************************************************************
        // The funtion that prints the page number
        //*****************************************************************************
        private void DrawPageNumber(Graphics g)
        {
            //mCurrentY = (float)this.mPageMargins.Top;
            float pagePrintWidth = this.DoGetPrintableWidth();

            //-------------------------------------------------------------
            // Printing the page number (if isWithPaging is set to true)
            //-------------------------------------------------------------
            if (mIsWithPaging)
            {
                mPageNumber++;
                string pageString = "Page " + mPageNumber.ToString();

                StringFormat pageStringFormat = new StringFormat();
                pageStringFormat.Trimming = StringTrimming.Word;
                pageStringFormat.FormatFlags = StringFormatFlags.NoWrap
                                             | StringFormatFlags.LineLimit
                                             | StringFormatFlags.NoClip;
                //pageStringFormat.Alignment = StringAlignment.Far;
                pageStringFormat.Alignment = StringAlignment.Center;

                Font pageStringFont = new Font("Tahoma", 8
                                              , FontStyle.Regular
                                              , GraphicsUnit.Point);
                float pagePageStringHeight = g.MeasureString(pageString, pageStringFont).Height;
                float pageNumberX = (float)this.mPageMargins.Left;
                float pageNumberY = 0;
                bool bPrintAtBottom = true;
                if (bPrintAtBottom)
                {
                    pageNumberY = this.mPageHeight - this.mPageMargins.Bottom;
                    pageNumberY += pagePageStringHeight;
                }
                else
                {
                    pageNumberY = this.mPageMargins.Top;
                    pageNumberY -= pagePageStringHeight;
                }
                RectangleF pagePrintArea = new RectangleF(pageNumberX, pageNumberY,
                                                          pagePrintWidth, pagePageStringHeight);

                g.DrawString(pageString, pageStringFont, new SolidBrush(Color.DarkGray)
                                       , pagePrintArea, pageStringFormat);

                //mCurrentY += g.MeasureString(pageString, pageStringFont).Height;
            }
        }

        //*****************************************************************************
        // The funtion that prints the title
        //*****************************************************************************
        private void DrawPageTitle(Graphics g)
        {
            float pagePrintWidth = this.DoGetPrintableWidth();
            if (mIsWithTitle)
            {
                StringFormat titleFormat = new StringFormat();
                titleFormat.Trimming = StringTrimming.Word;
                titleFormat.FormatFlags = StringFormatFlags.NoWrap
                                        | StringFormatFlags.LineLimit
                                        | StringFormatFlags.NoClip;

                float titleHt = g.MeasureString(mTheTitleText, mTheTitleFont).Height;

                float titleX = (float)this.mPageMargins.Left;
                float titleY = this.mPageMargins.Top
                             - titleHt * 1.8f;
                if (mIsCenterOnPage)
                {
                    titleFormat.Alignment = StringAlignment.Center; //HCenter
                    //titleFormat.LineAlignment = StringAlignment.Near;
                }
                else
                {
                    titleFormat.Alignment = StringAlignment.Near;   //Left
                    //titleFormat.LineAlignment = StringAlignment.Near;
                }

                RectangleF titleRectangle = new RectangleF(titleX, titleY, 
                                                           pagePrintWidth, titleHt);

                g.DrawString(mTheTitleText, mTheTitleFont, new SolidBrush(mTheTitleColor)
                                            , titleRectangle, titleFormat);

            }

        }

        //*****************************************************************************
        // The funtion that prints the title, page number, and the header row
        //*****************************************************************************
        private void DrawHeader(Graphics g)
        {
            mCurrentY = (float)this.mPageMargins.Top;
            float pagePrintWidth = this.DoGetPrintableWidth();

            //-------------------------------------------------------------
            // Printing the page number (if isWithPaging is set to true)
            //-------------------------------------------------------------
#if false
            if (mIsWithPaging)
            {
                mPageNumber++;
                string pageString = "Page " + mPageNumber.ToString();

                StringFormat pageStringFormat = new StringFormat();
                pageStringFormat.Trimming = StringTrimming.Word;
                pageStringFormat.FormatFlags = StringFormatFlags.NoWrap
                                             | StringFormatFlags.LineLimit
                                             | StringFormatFlags.NoClip;
                pageStringFormat.Alignment = StringAlignment.Far;

                Font pageStringFont = new Font("Tahoma", 8
                                              , FontStyle.Regular
                                              , GraphicsUnit.Point);
                float pagePageStringHeight = g.MeasureString(pageString, pageStringFont).Height;
                RectangleF pagePrintArea = new RectangleF((float)this.mPageMargins.Left, mCurrentY,
                                                          pagePrintWidth, pagePageStringHeight);

                g.DrawString(pageString, pageStringFont, new SolidBrush(Color.Black), pagePrintArea, pageStringFormat);

                //mCurrentY += g.MeasureString(pageString, pageStringFont).Height;
            }

            //-------------------------------------------------------------
            // Printing the title (if mIsWithTitle is set to true)
            //-------------------------------------------------------------
            if (mIsWithTitle)
            {
                StringFormat titleFormat = new StringFormat();
                titleFormat.Trimming = StringTrimming.Word;
                titleFormat.FormatFlags = StringFormatFlags.NoWrap
                                        | StringFormatFlags.LineLimit
                                        | StringFormatFlags.NoClip;
                if (mIsCenterOnPage)
                    titleFormat.Alignment = StringAlignment.Center;
                else
                    titleFormat.Alignment = StringAlignment.Near;

                float titleHt = g.MeasureString(mTheTitleText, mTheTitleFont).Height;
                RectangleF titleRectangle 
                    = new RectangleF((float)this.mPageMargins.Left, mCurrentY,
                                     pagePrintWidth, titleHt);

                g.DrawString(mTheTitleText, mTheTitleFont, new SolidBrush(mTheTitleColor)
                                            , titleRectangle, titleFormat);

                mCurrentY += g.MeasureString(mTheTitleText, mTheTitleFont).Height;
            }
#endif

            //-------------------------------------------------------------
            // printing the header itself
            //-------------------------------------------------------------
            if(mIsWithColHeaders)
            {
                // --- Setting the HeaderFore style
                Color headerForeColor = mTheDataGridView.ColumnHeadersDefaultCellStyle.ForeColor;
                if (headerForeColor.IsEmpty) // If there is no special HeaderFore style, then use the default DataGridView style
                    headerForeColor = mTheDataGridView.DefaultCellStyle.ForeColor;
                SolidBrush headerForeBrush = new SolidBrush(headerForeColor);

                // --- Setting the HeaderBack style
                Color headerBackColor = mTheDataGridView.ColumnHeadersDefaultCellStyle.BackColor;
                if (headerBackColor.IsEmpty) // If there is no special HeaderBack style, then use the default DataGridView style
                    headerBackColor = mTheDataGridView.DefaultCellStyle.BackColor;
                SolidBrush headerBackBrush = new SolidBrush(headerBackColor);

                // --- Setting the LinePen that will be used to draw lines and rectangles (derived from the GridColor property of the DataGridView control)
                Pen theLinePen = new Pen(mTheDataGridView.GridColor, 1);

                // --- Setting the HeaderFont style
                Font headerFont = mTheDataGridView.ColumnHeadersDefaultCellStyle.Font;
                if (headerFont == null) // If there is no special HeaderFont style, then use the default DataGridView font style
                    headerFont = mTheDataGridView.DefaultCellStyle.Font;

                //-------------------------------------------------------------
                // Calculating and drawing the HeaderBounds        
                //-------------------------------------------------------------
                // --- Calculating the starting x coordinate that the printing process 
                //     will start from
                float currentX = (float)this.mPageMargins.Left;
                float colRangeWidth = mColumnRangeWidth[mColumnRangeCur];
                if (mIsCenterOnPage)
                {
                    currentX += (pagePrintWidth - colRangeWidth) / 2.0F;
                }

                //--- fill the background of the header area
                RectangleF headerBounds = new RectangleF(currentX, mCurrentY,
                                            colRangeWidth, mColHeaderHeight);
                //headerBounds.Inflate(this.mCellMargins.Left, this.mCellMargins.Top);
                g.FillRectangle(headerBackBrush, headerBounds);

                //--- Set the format that will be used to print each cell of the header row
                StringFormat cellFormat = new StringFormat();
                cellFormat.Trimming = StringTrimming.Word;
                cellFormat.FormatFlags = StringFormatFlags.NoWrap
                                       | StringFormatFlags.LineLimit
                                       | StringFormatFlags.NoClip;

                //--- Print each visible cell of the header row
                RectangleF cellBounds;
                float columnWidth;
                for (int iCol = (int)mColumnRange[mColumnRangeCur].GetValue(0);
                         iCol < (int)mColumnRange[mColumnRangeCur].GetValue(1);
                         iCol++)
                {
                    if (!mTheDataGridView.Columns[iCol].Visible)
                        continue; // If the column is not visible then ignore this iteration

                    columnWidth = mColumnWidthPadded[iCol];

                    //--- Check the CurrentCell alignment and apply it to the CellFormat
                    if (mTheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Right"))
                        cellFormat.Alignment = StringAlignment.Far;
                    else if (mTheDataGridView.ColumnHeadersDefaultCellStyle.Alignment.ToString().Contains("Center"))
                        cellFormat.Alignment = StringAlignment.Center;
                    else
                        cellFormat.Alignment = StringAlignment.Near;

                    //--- set the bounding rectangle for the header cell
                    cellBounds = new RectangleF(currentX, mCurrentY,
                                                columnWidth, mColHeaderHeight);
                    cellBounds.Offset(this.mCellMargins.Left, this.mCellMargins.Top);

                    // Printing the cell text
                    g.DrawString(mTheDataGridView.Columns[iCol].HeaderText, headerFont
                                        , headerForeBrush, cellBounds, cellFormat);

                    // Drawing the cell bounds
                    //   only if the HeaderBorderStyle is not None
                    if (mTheDataGridView.RowHeadersBorderStyle != DataGridViewHeaderBorderStyle.None)
                    {
                        g.DrawRectangle(theLinePen, currentX, mCurrentY,
                                                    columnWidth, mColHeaderHeight);
                    }

                    currentX += columnWidth;
                }

                mCurrentY += mColHeaderHeight;
            }
        }

        //*****************************************************************************
        // The function that print a bunch of rows that fit in one page
        // When it returns true, meaning that there are more rows still not printed, 
        //   so another PagePrint action is required
        // When it returns false, meaning that all rows are printed (the mCurrentRow 
        //   parameter reaches the last row of the DataGridView control) and no further 
        //   PagePrint action is required
        //*****************************************************************************
        private bool DrawRows(Graphics g)
        {
            //--- Set the LinePen that will be used to draw lines and rectangles 
            //    (derived from the GridColor property of the DataGridView control)
            Pen theLinePen = new Pen(mTheDataGridView.GridColor, 1);

            //--- Set the style parameters that will be used to print each cell
            Font rowFont;
            Color rowForeColor;
            Color rowBackColor;
            SolidBrush rowForeBrush;
            SolidBrush rowBackBrush;
            SolidBrush rowAlternatingBackBrush;

            //--- Set the format that will be used to print each cell
            StringFormat cellFormat = new StringFormat();
            cellFormat.Trimming = StringTrimming.Word;
            cellFormat.Trimming = StringTrimming.EllipsisCharacter;
            cellFormat.FormatFlags = StringFormatFlags.NoWrap 
                                   | StringFormatFlags.LineLimit;
                                       //| StringFormatFlags.LineLimit
                                       //| StringFormatFlags.NoClip;

            //--- Print each visible cell
            RectangleF rowBounds;
            float currentX;
            float columnWidth;

            bool bUpdateColumnCount = true;
            int nColsPrinted = 0;

            while (mCurrentRow < mTheDataGridView.Rows.Count)
            {
                float rowHeight = mRowHeight[mCurrentRow];

                if (mTheDataGridView.Rows[mCurrentRow].Visible) // Print the cells of the CurrentRow only if that row is visible
                {
                    //--- Set the row font style
                    rowFont = mTheDataGridView.Rows[mCurrentRow].DefaultCellStyle.Font;
                    if (rowFont == null) // If the there is no special font style of the CurrentRow, then use the default one associated with the DataGridView control
                        rowFont = mTheDataGridView.DefaultCellStyle.Font;

                    //--- Set the RowFore style
                    rowForeColor = mTheDataGridView.Rows[mCurrentRow].DefaultCellStyle.ForeColor;
                    //      If the there is no special RowFore style of the CurrentRow, 
                    //      then use the default one associated with the DataGridView control
                    if (rowForeColor.IsEmpty) 
                        rowForeColor = mTheDataGridView.DefaultCellStyle.ForeColor;
                    rowForeBrush = new SolidBrush(rowForeColor);

                    //--- Set the RowBack (for even rows) and the RowAlternatingBack (for odd rows) styles
                    rowBackColor = mTheDataGridView.Rows[mCurrentRow].DefaultCellStyle.BackColor;
                    //      If the there is no special RowBack style of the CurrentRow, 
                    //      then use the default one associated with the DataGridView control
                    if (rowBackColor.IsEmpty) 
                    {
                        rowBackBrush = new SolidBrush(mTheDataGridView.DefaultCellStyle.BackColor);
                        rowAlternatingBackBrush = new SolidBrush(mTheDataGridView.AlternatingRowsDefaultCellStyle.BackColor);
                    }
                    else 
                    {
                        // If the there is a special RowBack style of the CurrentRow, 
                        // then use it for both the RowBack and the RowAlternatingBack styles
                        rowBackBrush = new SolidBrush(rowBackColor);
                        rowAlternatingBackBrush = new SolidBrush(rowBackColor);
                    }

                    //--- Calculate the starting X coordinate that the printing process 
                    //    will start from
                    currentX = (float)this.mPageMargins.Left;
                    float pagePrintWidth = this.DoGetPrintableWidth();
                    float colRangeWidth = mColumnRangeWidth[mColumnRangeCur];
                    if (mIsCenterOnPage)
                        currentX += (pagePrintWidth - colRangeWidth) / 2.0F;

                    //--- Calculate the entire CurrentRow bounds                
                    rowBounds = new RectangleF(currentX, mCurrentY, 
                                               colRangeWidth, rowHeight);

                    //--- Fill the back of the CurrentRow
                    if (mCurrentRow % 2 == 0)
                        g.FillRectangle(rowBackBrush, rowBounds);
                    else
                        g.FillRectangle(rowAlternatingBackBrush, rowBounds);

                    //--- Print each visible cell of the CurrentRow                
                    int colStart = (int)mColumnRange[mColumnRangeCur].GetValue(0);
                    int colEnd = (int)mColumnRange[mColumnRangeCur].GetValue(1);
                    for (int iCol = colStart; iCol < colEnd; iCol++)
                    {
                        // If the cell is belong to invisible column, 
                        // then ignore this iteration
                        if (!mTheDataGridView.Columns[iCol].Visible)
                            continue;

                        Type cellType = mTheDataGridView.Columns[iCol].CellType;
                        bool bCellIsAnImage 
                            = (cellType.ToString() == "System.Windows.Forms.DataGridViewImageCell");
                        
                        // Adjust the height of the row if there is an image
                        if (bCellIsAnImage)     //REWORK
                        {
                            if (mTheDataGridView.Rows[this.mCurrentRow].Cells[iCol].Value != null)
                            {
                                Image mTempImage = (Image)mTheDataGridView.Rows[mCurrentRow].Cells[iCol].Value;
                                if (mTempImage.Height > rowHeight)
                                    rowHeight = mTempImage.Height;
                            }
                        }

                        // Check the CurrentCell alignment and apply it to the CellFormat
                        if (mTheDataGridView.Columns[iCol].DefaultCellStyle.Alignment.ToString().Contains("Right"))
                            cellFormat.Alignment = StringAlignment.Far;
                        else if (mTheDataGridView.Columns[iCol].DefaultCellStyle.Alignment.ToString().Contains("Center"))
                            cellFormat.Alignment = StringAlignment.Center;
                        else
                            cellFormat.Alignment = StringAlignment.Near;

                        columnWidth = mColumnWidthPadded[iCol];
                        RectangleF cellBounds = new RectangleF(currentX, mCurrentY, 
                                                               columnWidth, rowHeight);
                        
                        //Printing the cell text OR draw the image
                        if (bCellIsAnImage)
                        {
                            // Only try drawing the image if one is assigned to the cell
                            if (mTheDataGridView.Rows[mCurrentRow].Cells[iCol].Value != null)
                            {
                                Image img = (Image)mTheDataGridView.Rows[mCurrentRow].Cells[iCol].Value;
                                g.DrawImage(img, (float)currentX, (float)mCurrentY, 
                                                 (float)columnWidth, (float)rowHeight);
                            }
                        }
                        else
                        {
                            // There was no image, so just draw the text
                            //cellBounds.Inflate(-mCellMargins.Left, -mCellMargins.Top);   //REWORK
                            cellBounds.Offset(mCellMargins.Left, mCellMargins.Top);   //REWORK
                            string cellValue = mTheDataGridView.Rows[mCurrentRow].Cells[iCol].EditedFormattedValue.ToString();
                            g.DrawString(cellValue, rowFont, rowForeBrush, cellBounds, cellFormat);
                        }

                        //--- Draw the cell's bounds
                        if (mTheDataGridView.CellBorderStyle != DataGridViewCellBorderStyle.None) // Draw the cell border only if the CellBorderStyle is not None
                            g.DrawRectangle(theLinePen, currentX, mCurrentY, 
                                                        columnWidth, rowHeight);

                        currentX += columnWidth;
                        if(bUpdateColumnCount)
                            nColsPrinted++;
                    }
                    
                    bUpdateColumnCount = false;
                    mCurrentY += rowHeight;

                    // Checking if the CurrentY is exceeds the page boundries
                    // If so then exit the function and returning true 
                    // meaning another PagePrint action is required
//                    if ((int)mCurrentY > (mPageHeight - this.mPageMargins.Top - this.mPageMargins.Bottom))
                    if ((int)this.mCurrentY > this.DoGetPrintableHeight())
                    {
                        mCurrentRow++;
                        return true;
                    }
                }
                mCurrentRow++;
            }

            //if (true)
            //{
            //    string sMsg = String.Format("DrawRows:DGV.Rows={0}; Row={1}", mTheDataGridView.Rows.Count, this.mCurrentRow);
            //    Debug.WriteLine(sMsg);
            //}

            mCurrentRow = 0;
            // Continue to print the next group of columns
            mColumnRangeCur ++; //= nColsPrinted;

            if (mColumnRangeCur >= mColumnRange.Count) // Which means all columns are printed
            {
                mColumnRangeCur = 0;
                return false;
            }
            else
                return true;
        }

        //*****************************************************************************
        // The method that calls all other functions
        //*****************************************************************************
        private bool DrawDataGridView(Graphics g)
        {
            bool bContinue;
            try
            {
                Calculate(g);
                DrawHeader(g);
                DrawPageTitle(g);
                DrawPageNumber(g);
                bContinue = DrawRows(g);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Operation failed: " + ex.Message.ToString(), Application.ProductName + " - Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                bContinue = false;
            }
            return bContinue;
        }

        //*****************************************************************************
        //*****************************************************************************
        public bool SetupThePrinting(bool bPreview)
        {
            if (mPrintDlg == null)
            {
                mPrintDlg = new PrintDialog();
                //set the default
                mPrintDlg.AllowCurrentPage = false;
                mPrintDlg.AllowPrintToFile = false;
                mPrintDlg.AllowSelection = false;
                mPrintDlg.AllowSomePages = false;
                mPrintDlg.PrintToFile = false;
                mPrintDlg.ShowHelp = false;
                mPrintDlg.ShowNetwork = false;
                mPrintDlg.UseEXDialog = true;
                //mPrintDlg.PrinterSettings.
            }

            //--- now get the options from the user
            if (DialogResult.OK == mPrintDlg.ShowDialog())
            {
                mPrintDoc.DocumentName = this.mNameOfClient + ":" + this.PageTitle;
                mPrintDoc.PrinterSettings = mPrintDlg.PrinterSettings;
                mPrintDoc.DefaultPageSettings = mPrintDlg.PrinterSettings.DefaultPageSettings;
                
                if(this.mPageMargins.Left!=0 && this.mPageMargins.Top != 0)
                    mPrintDoc.DefaultPageSettings.Margins = mPageMargins;

                if (true)
                {
                    // Calculating the PageWidth and the PageHeight
                    if (!mPrintDoc.DefaultPageSettings.Landscape)
                    {
                        mPageWidth = mPrintDoc.DefaultPageSettings.PaperSize.Width;
                        mPageHeight = mPrintDoc.DefaultPageSettings.PaperSize.Height;
                    }
                    else
                    {
                        mPageHeight = mPrintDoc.DefaultPageSettings.PaperSize.Width;
                        mPageWidth = mPrintDoc.DefaultPageSettings.PaperSize.Height;
                    }

                    //--- Calculate the page margins
                    this.mPageMargins = mPrintDoc.DefaultPageSettings.Margins;
                }

                if (bPreview)
                {
                    PrintPreviewDialog previewDlg = new PrintPreviewDialog();
                    previewDlg.Document = this.mThePrintDocument;
                    previewDlg.ShowDialog();
                }
                else
                {
                    this.mThePrintDocument.Print();
                }

                return true;
            }
            else
            {
                return false;
            }
        }

        private void OnPrintPage(object sender, PrintPageEventArgs e)
        {
            bool more = this.DrawDataGridView(e.Graphics);
            if (more == true)
                e.HasMorePages = true;
            else
            {
                this.mPageNumber = 0;    //reset it
                this.mCurrentRow = 0;
                this.mColumnRangeCur = 0;
                this.DoInit();
            }
        }

    }
    #endregion //DGVPrinter
    
    #region VVX.Print Wrapper
    class Print
    {
        #region Enums
        public enum HowToPrintDGV
        {
            Everything,
            SelectedColumns
        }
        #endregion //Enums

        #region Member Variables (Private)
        //PrintDocument mPrintDoc;
        //PrintDialog mPrintDlg;

        private DataGridView mDGV;
        private bool mbPrint;
        private string msTitle = "";
        private bool mbPrintSetup;
        private bool mbPrintPreview;
        private HowToPrintDGV mPrintHowDGV = HowToPrintDGV.Everything;
        #endregion //Member Variables (Private)

        #region Properties (Public)
        /// <summary>
        /// Set or Get the DataGridView [to be] printed
        /// </summary>
        public DataGridView PrintWhichDGV
        {
            get { return mDGV; }
            set { mDGV = value; }
        }

        public HowToPrintDGV PrintHowDGV
        {
            get { return mPrintHowDGV; }
            set { mPrintHowDGV = value; }
        }
        private string msPrintJobName = "VVX.Print";

        /// <summary>
        /// Name of the print job displayed by Windows, Drivers, or the Printer itself, etc.
        /// </summary>
        public string PrintJobName
        {
            get { return msPrintJobName; }
            set { msPrintJobName = value; }
        }

        /// <summary>
        /// Determines if the Print Setup Dialog is displayed before printing or previewing
        /// </summary>
        public bool PrintSetup
        {
            get { return mbPrintSetup; }
            set { mbPrintSetup = value; }
        }

        /// <summary>
        /// Determines if Previewing occurs before printing
        /// </summary>
        public bool PrintPreview
        {
            get { return mbPrintPreview; }
            set { mbPrintPreview = value; }
        }

        /// <summary>
        /// Name of the print job displayed by Windows, Drivers, or the Printer itself, etc.
        /// </summary>
        public string PrintTitle
        {
            get { return msTitle; }
            set { msTitle = value; }
        }
        #endregion //Properties (Public)

        #region Constructors
        /// <summary>
        /// Constructor (mainly for using PrintControl)
        /// </summary>
        public Print()
        {
        }

        /// <summary>
        /// Constructor for printing contents of a DataGridView
        /// </summary>
        /// <param name="dgv"></param>
        /// <param name="bSetup"></param>
        /// <param name="bPreview"></param>
        /// <param name="bPrint"></param>
        public Print(DataGridView dgv, bool bSetup, bool bPreview, bool bPrint)
        {
            this.mDGV = dgv;
            this.mbPrintSetup = bSetup;
            this.mbPrintPreview = bPreview;
            this.mbPrint = bPrint;
        }
        #endregion //Constructors

        #region Methods (Public)
        /// <summary>
        /// Prints the contents of the DataGridView 
        /// </summary>
        /// <returns></returns>
        public bool DoPrintDGV()
        {
            bool bRet = false;
            string sMsg = "";
            string sEOL = Environment.NewLine;
            if (this.mDGV != null)
            {
                switch (this.mPrintHowDGV)
                {
                    default:
                    case HowToPrintDGV.Everything:
                        // Use VVX.Print class DGVPrinter 
                        //      Adapted from "The DataGridViewPrinter Class", By Salan Al-Ani. 
                        //      See http://www.codeproject.com/csharp/datagridviewprinter.asp 
                        VVX.DGVPrinter dgvPrint = new DGVPrinter(this.mDGV);
                        dgvPrint.NameOfClient = this.PrintJobName;
                        dgvPrint.PageTitle = this.PrintTitle;
                        if (dgvPrint != null)
                        {
                            bRet = dgvPrint.SetupThePrinting(this.mbPrintPreview);
                        }
                        break;

                    case HowToPrintDGV.SelectedColumns:
                        // Use VVX.Print class PrintDGV
                        //      Adapted from "DataGridView Printing by Selecting Columns and Rows", By Afrasiab Cheraghi
                        //      See http://www.codeproject.com/csharp/PrintDataGridView.asp
                        bRet = PrintDGV.Print_DataGridView(this.mDGV, this.PrintTitle);
                        break;
                }
            }
            else
            {
                sMsg = "You need to initialize 'VVX.Print.mDGV'"
                     + " either with an appropriate constructor"
                     + " or with the VVX.Print.PrintWhichDGV property" + sEOL;
                MsgBox.Error(sMsg);
                Debug.WriteLine(sMsg);
            }

            sMsg += String.Format("VVX.Print successful? {0} ", bRet.ToString());
            Debug.WriteLine(sMsg);
            return bRet;
        }

        /// <summary>
        /// Displays a PrintDialog and allows the user to choose a printer
        /// and various settings (such as orientation)
        /// </summary>
        /// <param name="printDocSettings">PrinterSettings settings to be used by the PrintDocument</param>
        /// <returns>'true' if user clicked 'Print' in the PrintDialog, 'false' otherwise</returns>
        public bool DoGetPrinterAndSettingsFromUser(PrinterSettings printDocSettings)
        {
            PrintDialog printDlg = new PrintDialog();

            if (printDlg != null)
            {
                printDlg.PrinterSettings = printDocSettings;

                //--- now get the options from the user
                if (DialogResult.OK != printDlg.ShowDialog())
                {
                    return false;
                }
                else
                {
                    //--- update the settings
                    printDocSettings = printDlg.PrinterSettings;
                    return true;
#if !true
                    if (mPrintDoc == null)
                    {
                        this.mPrintDoc = new PrintDocument();
                        this.mPrintDoc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.OnPrintPage);
                    }
                    mPrintDoc.DocumentName = this.nameOfClient + ":" + this.PageTitle;
                    mPrintDoc.PrinterSettings = mPrintDlg.PrinterSettings;
                    mPrintDoc.DefaultPageSettings = mPrintDlg.PrinterSettings.DefaultPageSettings;

                    if (this.mPageMargins.Left != 0 && this.mPageMargins.Top != 0)
                        mPrintDoc.DefaultPageSettings.Margins = mPageMargins;

                    if (true)
                    {
                        // Calculating the PageWidth and the PageHeight
                        if (!mPrintDoc.DefaultPageSettings.Landscape)
                        {
                            mPageWidth = mPrintDoc.DefaultPageSettings.PaperSize.Width;
                            mPageHeight = mPrintDoc.DefaultPageSettings.PaperSize.Height;
                        }
                        else
                        {
                            mPageHeight = mPrintDoc.DefaultPageSettings.PaperSize.Width;
                            mPageWidth = mPrintDoc.DefaultPageSettings.PaperSize.Height;
                        }

                        //--- Calculate the page margins
                        this.mPageMargins = mPrintDoc.DefaultPageSettings.Margins;
                    }

                    if (bPreview)
                    {
                        PrintPreviewDialog previewDlg = new PrintPreviewDialog();
                        previewDlg.Document = this.mThePrintDocument;
                        previewDlg.ShowDialog();
                    }
                    else
                    {
                        this.mThePrintDocument.Print();
                    }

                    return true;
#endif
                }
            }

            return false;
        }

        public void DoPrintControl(Control controlToPrint
                        , bool bSetup, bool bPreview, bool bPrint, bool bDoNotResize)
        {
            try
            {
                int width = controlToPrint.Width;
                int height = controlToPrint.Height;
                ControlPrint printDoc = new ControlPrint(controlToPrint, width, height, bDoNotResize);

                bool bOk = true;
                //bool bTemp;

                //bTemp = printDoc.PrinterSettings.DefaultPageSettings.Landscape;

                if (bSetup)
                {
                    bOk = this.DoGetPrinterAndSettingsFromUser(printDoc.PrinterSettings);
                }
                
                //bTemp = printDoc.PrinterSettings.DefaultPageSettings.Landscape;

                if (bOk)
                {
                    if (bPreview)
                    {
                        PrintPreviewDialog ppvDlg = new PrintPreviewDialog(); ;
                        ppvDlg.Document = (PrintDocument)printDoc;
                        ppvDlg.ShowDialog();
                    }
                    else
                    {
                        printDoc.Print();
                    }
                }
            }
            catch (Exception ex)
            {
                MsgBox.Error(ex.ToString());
            }
        }
        #endregion //Methods (Public)

    }
    #endregion //VVX.Print Wrapper
}

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
An old dog trying to learn new tricks!

Comments and Discussions