protected override void OnPrintPage(PrintPageEventArgs e)
		{
			base.OnPrintPage(e);
			if (m_PageCount == 0)
			{
				m_HeaderHeight = this.GetHeaderHeight(e.Graphics);
				m_TitleHeight = this.GetTitleHeight(e.Graphics);
				m_FooterHeight = this.GetFooterHeight(e.Graphics);
				m_PageCount = this.PrecalculatePageCount(e);
				m_PageNo = 1;
			}

			if (m_RangeToPrint.IsEmpty())
				return;

			if ( m_BorderPen == null )
				m_BorderPen = new Pen(Color.Black);

			RectangleF area = new RectangleF(e.MarginBounds.Left,
			                                 e.MarginBounds.Top + m_HeaderHeight + (m_NextRowToPrint == RangeToPrint.Start.Row ? m_TitleHeight : 0),
			                                 e.MarginBounds.Width,
			                                 e.MarginBounds.Height - m_HeaderHeight - (m_NextRowToPrint == RangeToPrint.Start.Row ? m_TitleHeight : 0) - m_FooterHeight);

			this.DrawHeader(e.Graphics, new RectangleF(e.MarginBounds.Left, e.MarginBounds.Top, e.MarginBounds.Width, m_HeaderHeight),
			                m_PageNo, m_PageCount);

			if ( m_PageNo == 1 )
				this.DrawTitle(e.Graphics, new RectangleF(e.MarginBounds.Left, e.MarginBounds.Top + m_HeaderHeight, e.MarginBounds.Width, m_TitleHeight),
				               m_PageNo, m_PageCount);

			List<int> columnHasTopBorder = new List<int>();
			List<int> rowHasLeftBorder = new List<int>();
			RangeCollection printedRanges = new RangeCollection();

			int pageFirstRow = m_NextRowToPrint;
			int pageFirstColumn = m_NextColumnToPrint;
			int pageLastColumn = RangeToPrint.End.Column;

			// Pre-calculate width of the table in current page
			float pageColumnWidth = 0;
			for ( int i = m_NextColumnToPrint; i <= RangeToPrint.End.Column; i++ )
			{
				float colWidth = this.GetColumnWidth(e.Graphics, i);
				if ( i == m_NextColumnToPrint && colWidth > area.Width )
					colWidth = area.Width;
				if ( pageColumnWidth + colWidth <= area.Width )
					pageColumnWidth += colWidth;
				else
					break;
			}

			// Support for fixed row repeat
			if ( RepeatFixedRows && m_Grid.ActualFixedRows > RangeToPrint.Start.Row )
				m_NextRowToPrint = RangeToPrint.Start.Row;

			float curY = area.Top;
			while (m_NextRowToPrint <= RangeToPrint.End.Row)
			{
				// If repeated rows are printed, resume printing next rows
				if ( RepeatFixedRows && m_NextRowToPrint >= m_Grid.ActualFixedRows && m_NextRowToPrint < pageFirstRow )
					m_NextRowToPrint = pageFirstRow;
				float rowHeight = this.GetRowHeight(e.Graphics, m_NextRowToPrint);
				// Check if row fits in current page
				if ( curY + rowHeight > area.Bottom )
					break;
				float curX = area.Left;
				while (m_NextColumnToPrint <= pageLastColumn)
				{
					float colWidth = this.GetColumnWidth(e.Graphics, m_NextColumnToPrint);
					// Check if column fits in current page
					if ( curX + colWidth > area.Right )
					{
						// If single column does not fit in page, force it
						if ( m_NextColumnToPrint == pageFirstColumn )
							colWidth = area.Right - curX;
						else
						{
							pageLastColumn = m_NextColumnToPrint - 1;
							break;
						}
					}
					RectangleF cellRectangle;
					Position pos = new Position(m_NextRowToPrint, m_NextColumnToPrint);
					Range range = m_Grid.PositionToCellRange(pos);

					// Check if cell is spanned
					if ( range.ColumnsCount > 1 || range.RowsCount > 1 )
					{
						Size rangeSize = m_Grid.RangeToSize(range);
						// Is the first position, draw allways
						if ( range.Start == pos )
						{
							cellRectangle = new RectangleF(curX, curY, rangeSize.Width, rangeSize.Height);
							printedRanges.Add(range);
						}
						else
						{
							// Draw only if this cell is not already drawn on current page
							if ( ! printedRanges.ContainsCell(pos) )
							{
								// Calculate offset
								float sX = curX;
								for (int i = pos.Column - 1; i >= range.Start.Column; i--)
								{
									float cw = this.GetColumnWidth(e.Graphics, i);
									sX -= cw;
								}
								float sY = curY;
								for ( int i = pos.Row - 1; i >= range.Start.Row; i-- )
								{
									float cw = this.GetRowHeight(e.Graphics, i);
									sY -= cw;
								}
								cellRectangle = new RectangleF(sX, sY, rangeSize.Width, rangeSize.Height);
								printedRanges.Add(range);
							}
							else
								cellRectangle = RectangleF.Empty;
						}
					}
					else
					{
						cellRectangle = new RectangleF(curX, curY, colWidth, rowHeight);
					}

					if ( ! cellRectangle.IsEmpty )
					{
						SourceGrid.Cells.ICellVirtual cell = this.m_Grid.GetCell(pos);
						if ( cell != null )
						{
							CellContext ctx = new CellContext(m_Grid, pos, cell);
							RectangleF clip = new RectangleF(Math.Max(cellRectangle.Left, area.Left),
							                                 Math.Max(cellRectangle.Top, area.Top),
							                                 Math.Min(cellRectangle.Right, area.Left + pageColumnWidth) - Math.Max(cellRectangle.Left, area.Left),
							                                 Math.Min(cellRectangle.Bottom, area.Bottom) - Math.Max(cellRectangle.Top, area.Top));
							Region prevClip = e.Graphics.Clip;
							try
							{
								e.Graphics.Clip = new Region(clip);
								this.DrawCell(e.Graphics, ctx, cellRectangle);
							}
							finally
							{
								// Restore clip region
								e.Graphics.Clip = prevClip;
							}
							// Check if left border can be drawn in current page
							if ( ! ContainsInRange(rowHasLeftBorder, range.Start.Row, range.End.Row)
							    && cellRectangle.Left >= area.Left )
							{
								e.Graphics.DrawLine(m_BorderPen, cellRectangle.Left, clip.Top, cellRectangle.Left, clip.Bottom);
								AddRange(rowHasLeftBorder, range.Start.Row, range.End.Row);
							}
							// Check if top border can be drawn in current page
							if ( ! ContainsInRange(columnHasTopBorder, range.Start.Column, range.End.Column)
							    && cellRectangle.Top >= area.Top )
							{
								e.Graphics.DrawLine(m_BorderPen, clip.Left,	cellRectangle.Top, clip.Right, cellRectangle.Top);
								AddRange(columnHasTopBorder, range.Start.Column, range.End.Column);
							}
							// Check if right border can be drawn in current page
							if ( cellRectangle.Right <= area.Right )
								e.Graphics.DrawLine(m_BorderPen, cellRectangle.Right, clip.Top, cellRectangle.Right, clip.Bottom);
							// Check if bottom border can be drawn in current page
							if ( cellRectangle.Bottom <= area.Bottom )
								e.Graphics.DrawLine(m_BorderPen, clip.Left, cellRectangle.Bottom, clip.Right, cellRectangle.Bottom);
						}
					}
					// Set next column position
					curX += colWidth;
					m_NextColumnToPrint++;
				}
				// Set next row Y position
				curY += rowHeight;
				m_NextRowToPrint++;
				m_NextColumnToPrint = pageFirstColumn;
			}
			// If we have not reached last column, we will continue on next page
			if ( pageLastColumn != RangeToPrint.End.Column )
			{
				m_NextRowToPrint = pageFirstRow;
				m_NextColumnToPrint = pageLastColumn + 1;
			}
			else
				m_NextColumnToPrint = RangeToPrint.Start.Column;

			this.DrawFooter(e.Graphics, new RectangleF(e.MarginBounds.Left, e.MarginBounds.Bottom - m_FooterHeight, e.MarginBounds.Width, m_FooterHeight),
			                m_PageNo, m_PageCount);
			
			// If we have not reached last row we will continue on next page
			e.HasMorePages = (m_NextRowToPrint <= RangeToPrint.End.Row);
			// If there are no more pages, release resources
			if ( e.HasMorePages )
				m_PageNo++;
		}