I have searched EXTENSIVELY on a solution to this issue but have not been able to find anything that can be used with my current code.
I have a form application that performs a query against a SQL Server table and populates a dataGridView
with the rows. I then have a button to print the dataGridView
to a printer. I've gotten so far as to embed an override of the printPreviewDialog
print button with a printDialog
, and I've also gotten the "print page range" field unblocked, but giving a page range still prints all of the pages of a dataGridView
. For example if my dataGridView
is going to print 20 pages, and I select pages 2-4 in the range, I still get all 20 pages.
I've seen some examples with the DocumentPaginator
but I'm not using a document I'm printing directly from the dataGridView
and at this point I'm stuck.
Below is all of my code for printing the dataGridView
.
private void printActivityReportToolStripMenuItem_Click(object sender, EventArgs e)
{
PrintPreviewDialog objPPdialog = new PrintPreviewDialog();
objPPdialog.Document = printDocument1;
ToolStrip ts = new ToolStrip();
ts.Name = "wrongToolStrip";
foreach (Control ctl in objPPdialog.Controls)
{
if (ctl.Name.Equals("toolStrip1"))
{
ts = ctl as ToolStrip;
break;
}
}
ToolStripButton printButton = new ToolStripButton();
foreach (ToolStripItem tsi in ts.Items)
{
if (tsi.Name.Equals("printToolStripButton"))
{
printButton = tsi as ToolStripButton;
}
}
printButton.Click += new EventHandler(this.SelectPrinterAfterPreview);
ts.Items.Remove(printButton);
ToolStripButton b = new ToolStripButton();
b.ImageIndex = printButton.ImageIndex;
b.Visible = true;
ts.Items.Insert(0, b);
b.Click += new EventHandler(this.SelectPrinterAfterPreview);
printDocument1.DefaultPageSettings.Landscape = true;
//((ToolStripButton)((ToolStrip)objPPdialog.Controls[1]).Items[0]).
objPPdialog.ShowDialog();
}
private void SelectPrinterAfterPreview(object sender, EventArgs e)
{
PrintDialog printDialog = new PrintDialog();
printDialog.Document = printDocument1;
printDocument1.DefaultPageSettings.Landscape = true;
printDialog.AllowSomePages = true;
printDialog.UseEXDialog = true;
if (DialogResult.OK == printDialog.ShowDialog())
{
printDocument1.DocumentName = "Activity Report";
printDocument1.Print();
}
}
private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
try
{
strFormat = new StringFormat();
strFormat.Alignment = StringAlignment.Near;
strFormat.LineAlignment = StringAlignment.Center;
strFormat.Trimming = StringTrimming.EllipsisCharacter;
arrColumnLefts.Clear();
arrColumnWidths.Clear();
iCellHeight = 0;
iRow = 0;
bFirstPage = true;
bNewPage = true;
// Calculating Total Widths
iTotalWidth = 0;
foreach (DataGridViewColumn dgvGridCol in dataGridView1.Columns)
{
iTotalWidth += dgvGridCol.Width;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void printDocument1_PrintPage(object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
try
{
//Set the left margin
int iLeftMargin = e.MarginBounds.Left;
//Set the top margin
int iTopMargin = e.MarginBounds.Top;
//Whether more pages have to print or not
bool bMorePagesToPrint = false;
int iTmpWidth = 0;
//For the first page to print set the cell width and header height
if (bFirstPage)
{
foreach (DataGridViewColumn GridCol in dataGridView1.Columns)
{
iTmpWidth = (int)(Math.Floor((double)((double)GridCol.Width /
(double)iTotalWidth * (double)iTotalWidth *
((double)e.MarginBounds.Width / (double)iTotalWidth))));
iHeaderHeight = (int)(e.Graphics.MeasureString(GridCol.HeaderText,
GridCol.InheritedStyle.Font, iTmpWidth).Height) + 11;
// Save width and height of headers
arrColumnLefts.Add(iLeftMargin);
arrColumnWidths.Add(iTmpWidth);
iLeftMargin += iTmpWidth;
}
}
//Loop till all the grid rows not get printed
while (iRow <= dataGridView1.Rows.Count - 1)
{
DataGridViewRow GridRow = dataGridView1.Rows[iRow];
//Set the cell height
iCellHeight = GridRow.Height;
int iCount = 0;
//Check whether the current page settings allows more rows to print
if (iTopMargin + iCellHeight >= e.MarginBounds.Height + e.MarginBounds.Top)
{
bNewPage = true;
bFirstPage = false;
bMorePagesToPrint = true;
break;
}
else
{
if (bNewPage)
{
//Draw Header
e.Graphics.DrawString("Activity Report for "+txtBoxUsername.Text+"",
new Font(dataGridView1.Font, FontStyle.Bold),
Brushes.Black, e.MarginBounds.Left,
e.MarginBounds.Top - e.Graphics.MeasureString("Activity Report for " + txtBoxUsername.Text + "",
new Font(dataGridView1.Font, FontStyle.Bold),
e.MarginBounds.Width).Height - 13);
String strDate = DateTime.Now.ToLongDateString() + " " +
DateTime.Now.ToShortTimeString();
//Draw Date
e.Graphics.DrawString(strDate,
new Font(dataGridView1.Font, FontStyle.Bold), Brushes.Black,
e.MarginBounds.Left +
(e.MarginBounds.Width - e.Graphics.MeasureString(strDate,
new Font(dataGridView1.Font, FontStyle.Bold),
e.MarginBounds.Width).Width),
e.MarginBounds.Top - e.Graphics.MeasureString("Activity Report for " + txtBoxUsername.Text + "",
new Font(new Font(dataGridView1.Font, FontStyle.Bold),
FontStyle.Bold), e.MarginBounds.Width).Height - 13);
//Draw Columns
iTopMargin = e.MarginBounds.Top;
foreach (DataGridViewColumn GridCol in dataGridView1.Columns)
{
e.Graphics.FillRectangle(new SolidBrush(Color.LightGray),
new Rectangle((int)arrColumnLefts[iCount], iTopMargin,
(int)arrColumnWidths[iCount], iHeaderHeight));
e.Graphics.DrawRectangle(Pens.Black,
new Rectangle((int)arrColumnLefts[iCount], iTopMargin,
(int)arrColumnWidths[iCount], iHeaderHeight));
e.Graphics.DrawString(GridCol.HeaderText,
GridCol.InheritedStyle.Font,
new SolidBrush(GridCol.InheritedStyle.ForeColor),
new RectangleF((int)arrColumnLefts[iCount], iTopMargin,
(int)arrColumnWidths[iCount], iHeaderHeight), strFormat);
iCount++;
}
bNewPage = false;
iTopMargin += iHeaderHeight;
}
iCount = 0;
//Draw Columns Contents
foreach (DataGridViewCell Cel in GridRow.Cells)
{
if (Cel.Value != null)
{
Font font = new Font("Arial", 7);
e.Graphics.DrawString(Cel.Value.ToString(),font,new SolidBrush(Cel.InheritedStyle.ForeColor),new RectangleF((int)arrColumnLefts[iCount],(float)iTopMargin,(int)arrColumnWidths[iCount], (float)iCellHeight),strFormat);
}
//Drawing Cells Borders
e.Graphics.DrawRectangle(Pens.Black,
new Rectangle((int)arrColumnLefts[iCount], iTopMargin,
(int)arrColumnWidths[iCount], iCellHeight));
iCount++;
}
}
iRow++;
iTopMargin += iCellHeight;
}
//If more lines exist, print another page.
if (bMorePagesToPrint)
e.HasMorePages = true;
else
e.HasMorePages = false;
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
You are setting a fairly inflexible limitation by insisting a solution works with your existing code. Which was written completely without considering starting from a page other than 1. Not actually that hard to fix, you just have to figure out at what row in the datagrid you start, based on the start page number.
But what you ask for is possible. You can trick your existing code by creating a new PrintDocument that simply fakes the printing device context for the pages you want to skip. It won't know any better than it is actually printing them. Add a new class to your project and paste the code shown below. Build. Drop the new component from the top of the toolbox, replacing your existing PrintDocument. Set the PageFrom and PageTo properties in your code, based on the PrintDialog.PrinterSettings.PageFrom/To property values.
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Printing;
using System.Drawing.Imaging;
class PagedPrintDocument : PrintDocument {
public int PageFrom { get; set; }
public int PageTo { get; set; }
public int Page { get; private set; }
protected override void OnBeginPrint(PrintEventArgs e) {
Page = 0;
if (PageTo < PageFrom) e.Cancel = true;
base.OnBeginPrint(e);
}
protected override void OnPrintPage(PrintPageEventArgs e) {
while (++Page < PageFrom) {
// Fake the pages that need to be skipped by printing them to a Metafile
IntPtr hDev = e.Graphics.GetHdc();
try {
using (var mf = new Metafile(hDev, e.PageBounds))
using (var gr = Graphics.FromImage(mf)) {
var ppe = new PrintPageEventArgs(gr, e.MarginBounds, e.PageBounds, e.PageSettings);
base.OnPrintPage(ppe);
}
}
finally {
e.Graphics.ReleaseHdc(hDev);
}
}
// Print the real page
base.OnPrintPage(e);
// No need to continue past PageTo
if (PageTo > 0 && Page >= PageTo) e.HasMorePages = false;
}
}
You are almost there. Setting printDialog.AllowSomePages = true;
only enables the page selection controls in the print dialog. The changed print range has to be used while printing the DataGridView
.
Have class members to store the page range and print page count.
int fromPage=0;
int toPage=0;
int pageCount=0;
Get the changed page range after the PrintDialog
is accepted.
if (DialogResult.OK == printDialog.ShowDialog())
{
fromPage = printDialog.PrinterSettings.FromPage;
toPage = printDialog.PrinterSettings.ToPage;
printDocument1.DocumentName = "Activity Report";
printDocument1.Print();
}
Use the page range in the PrintPage
method
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
pageCount++;
if(pageCount >= fromPage)
{
// print your grid
}
if (bMorePagesToPrint && pageCount <= toPage)
e.HasMorePages = true;
else
e.HasMorePages = false;
}
If you want to use the page range for PrintPreviewDialog
, change the PrinterSettings
property of the PrintDocument
before setting the Document
property.
PrintPreviewDialog objPPdialog = new PrintPreviewDialog();
fromPage = 2;
toPage = 6;
objPPdialog.Document = printDocument1;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With