Implementing dialog box in ASP .NET based web application
By Zach Martin
Published: 3/2/2003
Reader Level: Intermediate
Rated: 3.50 by 4 member(s).
Tell a Friend
Rate this Article
Printable Version
Discuss in the Forums

Download in C# and Visual Basic .NET

The standard WinForm DataGrid control that is included with the .NET Framework does not inheritantly expose a method for printing its contents. Undoubtedly, there are several third party vendors that offer DataGrid components which include such support. However, this article will demonstrate that with relatively little code you can implement basic print functionality in a WinForm DataGrid.

To achieve this, we will create a custom DataGridPrintDocument class that is derived from the native System.Drawing.Printing.PrintDocument class and override both its OnBeginPrint and OnPrintPage methods. A simple WinForm with a DataGrid control, filled with data from the Customers table of the Northwind database, will act as our test client.

Creating the DataGridPrintDocument class

DataGridPrintDocument.cs

First, we declare some class level variables that will be used in our print job logic and create a class constructor that will take a DataGrid object as a parameter.

public class DataGridPrintDocument:PrintDocument
{
#region "Class Variables"
//DataGrid object of which contents are to be printed
private DataGrid _DataGrid;
//Total count of rows in datagrid or underlying grid datasource
private int _DataRowCount;
//Current datagrid row and col that was printed
private int _CurrentPrintRow;
private int _CurrentPrintCol;
//Current TableStyle of grid
private DataGridTableStyle _DataGridTableStyle;
//Fonts used during print
private Font _ColumnHeaderFont;
private Font _RecordFont;
//Boolean switch to determine if the CurrentPrintRow variable should be incrememented
//before breaking to a new page.

private bool _ResetPrintRow;
#endregion

public DataGridPrintDocument(DataGrid dataGrid)
{
_DataGrid=dataGrid;
}

Next, we override the OnBeginPrint method of the base PrintDocument class. This method is called only once, before the first page of our document prints, and is an ideal place to initialize any class level variables that will be used later during the print process (e.g. setting fonts, getting the current DataGrid TableStyle, getting the number of rows to be printed, etc.) Notice that we attempt to get the TableStyle of the current display member of our DataGrid. During the print process, we will use its GridColumnStyles collection to output the appropriate headers and correct width for each column. If the DataGrid does not have a TableStyle for the current display member, we call a support function of our class, CreateGridTableStyle, to create a TableStyle based on the underlying DataTable of our DataGrid.

protected override void OnBeginPrint(PrintEventArgs e)
{
base.OnBeginPrint(e);

//Initialize the current print row and column
_CurrentPrintRow = 0;
_CurrentPrintCol = 0;

//If fonts were not set, then use the default datagrid fonts.
if (_ColumnHeaderFont == null)
_ColumnHeaderFont = _DataGrid.HeaderFont;
if (_RecordFont == null)
_RecordFont = _DataGrid.Font;

string CurrentDisplayMember=GetCurrentGridDisplayMember();
_DataGridTableStyle=_DataGrid.TableStyles[CurrentDisplayMember];

//call support function of our class to create a temp TableStyle
//if one does not already exist for the current display member.

if (_DataGridTableStyle==null)
{
DataTable dt=new DataTable();
Type t=_DataGrid.DataSource.GetType();

if (t==typeof(DataSet))
dt=((DataSet)(_DataGrid.DataSource)).Tables[CurrentDisplayMember];
else if (t==typeof(DataView))
dt=((DataView)(_DataGrid.DataSource)).Table;
else
dt=(DataTable)(_DataGrid.DataSource);

_DataGridTableStyle=CreateGridTableStyle(dt);
}

//Get number of datarows displayed in grid
_DataRowCount = _DataGrid.BindingContext[_DataGrid.DataSource, _DataGrid.DataMember].Count;
}

Lastly, we override the OnPrintPage method of the base PrintDocument class. This method will be called for each page in our print job and will handle all the necessary logic for rendering the contents of our DataGrid. We first loop through the GridColumnStyles collection of the current TableStyle and output the header of each column using the value in the HeaderText property. We then loop through the rows of the DataGrid and write out the column values for each. Note that before writing out a new row to the page, we check to ensure its y location will not exceed the available space of the MarginBounds.Bottom property value. Similarly, we check each column to ensure its x location will not exceed the available space of the MarginBounds.Right property. If a new row or column will exceed the space on the current page, we break from the current loop and force a new page. Additionally, if there are more columns to print for the current row, we set the _ResetPrintRow value to false. This will cause the next page to begin its output at the correct row and column from the previous page. Finally, we check if an additional page is required and set the HasMorePages property of the PrintPageEventArgs object to the appropriate boolean value.

protected override void OnPrintPage(PrintPageEventArgs e)
{
base.OnPrintPage(e);

int RowIndex;
int ColIndex;
float x = e.PageSettings.Margins.Left;
float y = e.PageSettings.Margins.Top;
Brush brush=new SolidBrush(Color.Black);
//vertical spacing between column header and first row
private const float HEADER_SPACING_Y = 15;

//By default, set to true. Unless the datagrid columns will exceed the available space
//on the current print page, we always reset the CurrentPrintRow variable.

_ResetPrintRow = true;

//output the column headers of grid
for (ColIndex = _CurrentPrintCol; ColIndex < = _DataGridTableStyle.GridColumnStyles.Count-1; ColIndex++)
{
//Check to see if the next column will exceed the max available space on the current print page.
//If true, set the ResetPrintRow switch to false and break from the loop.

if ((x + _DataGridTableStyle.GridColumnStyles[ColIndex].Width) > = e.MarginBounds.Right)
{
_ResetPrintRow = false;
break;
}
else
{
string HeaderText=_DataGridTableStyle.GridColumnStyles[ColIndex].HeaderText;
e.Graphics.DrawString(HeaderText, _ColumnHeaderFont, brush, x, y);
x += _DataGridTableStyle.GridColumnStyles[ColIndex].Width;
}
}

//output the rows of datagrid
int i=0;
for (RowIndex = _CurrentPrintRow; RowIndex < = _DataRowCount-1; RowIndex++)
{
//reset new row x to left margin value
x = e.PageSettings.Margins.Left;
//Calculate y location for new row
y = e.PageSettings.Margins.Top + (HEADER_SPACING_Y + (i * _RecordFont.GetHeight(e.Graphics)));
//Check that the next row will not exceed the max available space on the current print page
if (y > = e.MarginBounds.Bottom)
break;
else //loop and print columns of the current row
{
for (ColIndex = _CurrentPrintCol; ColIndex < = _DataGridTableStyle.GridColumnStyles.Count-1; ColIndex++)
{
//Check that the next column will exceed the max available space on the current print page.
//If true, exit for and set ResetPrintRow switch to False.
if ((x + _DataGridTableStyle.GridColumnStyles[ColIndex].Width) > = e.MarginBounds.Right)
{
_ResetPrintRow = false;
break;
}
else //print on current page
{
string CellText="";
if (_DataGrid[RowIndex, ColIndex] != DBNull.Value) //check for null value
//get the current cell contents - replace any carriage line returns with empty space.
CellText=_DataGrid[RowIndex, ColIndex].ToString().Replace(Environment.NewLine," ");

e.Graphics.DrawString(CellText, _RecordFont, brush, x, y);
x += _DataGridTableStyle.GridColumnStyles[ColIndex].Width;
}
}
i += 1;
}
}

if (_ResetPrintRow==true)
{
//hold the last row we printed
_CurrentPrintRow = RowIndex;
//reset the print col back to the first column
_CurrentPrintCol = 0;
}
else
//hold the last column we printed
_CurrentPrintCol = ColIndex;

//Check if additional pages are to be printed
if (_CurrentPrintRow == _DataRowCount && _CurrentPrintCol == 0)
e.HasMorePages = false;
else
e.HasMorePages = true;
}

Using the DataGridPrintDocument

To test the custom DataGridPrintDocument class, we simply create an instance of it on our form and set it equal to the Document property of either the PrintPreviewDialog or PrintDialog components. The print document will render using the settings of the one TableStyle defined in the DataGrid.



Marketplace
(Sponsored Links)
What are the green links?
   



 
Copyright © 2007 CMP Tech LLC |
Privacy Policy (4/10/06) | Your California Privacy Rights (4/10/06) | Terms of Service | Advertising Info | About Us | Help