WinForms - 打印两个数据网格视图时,打印预览很好,但在纸上只打印第二个 dgv
Posted
技术标签:
【中文标题】WinForms - 打印两个数据网格视图时,打印预览很好,但在纸上只打印第二个 dgv【英文标题】:WinForms - When printing two datagridviews, print preview is good but on paper only 2nd dgv is printed 【发布时间】:2021-11-23 14:40:48 【问题描述】:我正在制作一个软件来帮助我工作。它读取两个 excel (xlsx) 文件并从中获取一些信息。然后将信息放在两个数据网格视图之一或两个数据网格视图中。
然后,当我打印 datagridviews 时,我需要显示一个数字。在打印预览中,一切都完全符合我的要求,但是在纸上打印时,它会删除(或不记得)关于第一个 datagridview 的所有内容以及我用它打印的所有内容,并从第二个 datagridview 开始。
它在打印预览中的显示方式如下:
但是当我把它打印在纸上时,我会变成这样
为什么第一个 datagridview 出现在纸上,但如果我将它从 Microsoft 打印 PDF 打印到 PDF,我会得到与预览完全相同的 PDF。
仅在纸上打印时出现问题。
这是我的打印代码https://pastebin.com/6ZF2FevZ
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Printing;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;
namespace Motabaka
class DGVsPrinter
private Font fontD;
private Brush brushD = Brushes.Black;
private bool dgv1Finished;
private string a3800, a1800;
public string Title get; set;
public bool IncludeDateAndTimeInFooter get; set;
public bool IncludePageNumberInFooter get; set;
public bool IncludeEndingPhraseAtTheEnd get; set;
public string EndingPhrase get; set; = "End";
private DataGridView dataGridView1, dataGridView2;
private int rowIndex;
private int cellCount;
private int pageNumber = 1;
private readonly PrintDocument printDoc;
private int iTotalWidth1;
private int iTotalWidth2;
private Dictionary<int, int> ColumntWidths;
private Dictionary<int, int> arrColumnWidths1 = new Dictionary<int, int>();
private Dictionary<int, int> arrColumnWidths2 = new Dictionary<int, int>();
private bool preview;
public DGVsPrinter(DataGridView dataGridView1, DataGridView dataGridView2, PrintDocument printDoc, string A3800, string A1800)
this.dataGridView1 = dataGridView1;
this.dataGridView2 = dataGridView2;
this.printDoc = printDoc;
fontD = new Font(dataGridView1.Font, FontStyle.Bold);
printDoc.BeginPrint += OnBeginPrint;
printDoc.PrintPage += OnPrintPage;
a3800 = A3800;
a1800 = A1800;
public void Print(bool preview = false)
this.preview = preview;
rowIndex = 0;
cellCount = 0;
pageNumber = 0;
var dgvs = new DataGridView[] dataGridView1, dataGridView2 ;
foreach (DataGridView dgv in dgvs)
var rows = dgv.Rows
.Cast<DataGridViewRow>()
.FirstOrDefault(r => !r.IsNewRow && r.Visible);
if (rows != null)
cellCount = rows.Cells
.Cast<DataGridViewCell>()
.Where(c => c.Visible)
.Count();
if (cellCount == 0)
//MessageBox.Show(new Form() FormBorderStyle = FormBorderStyle.None , "Nothing to print...");
continue;
if (cellCount == 0)
MessageBox.Show(new Form() FormBorderStyle = FormBorderStyle.None , "Nothing to print...");
return;
if (preview)
try
using (var pd = new PrintPreviewDialog())
pd.Document = printDoc;
pd.ShowDialog();
catch (Exception ex)
Error.Log(ex);
else
try
using (var pd = new PrintDialog())
pd.Document = printDoc;
if (pd.ShowDialog() == DialogResult.OK)
pd.Document.Print();
catch (Exception ex)
Error.Log(ex);
private void OnBeginPrint(object sender, PrintEventArgs e)
try
rowIndex = 0; pageNumber = 1;
iTotalWidth1 = 0;
iTotalWidth2 = 0;
arrColumnWidths1.Clear();
arrColumnWidths2.Clear();
foreach (DataGridViewColumn dgvGridCol in dataGridView1.Columns)
if (!dgvGridCol.Visible) continue;
iTotalWidth1 += dgvGridCol.Width;
foreach (DataGridViewColumn dgvGridCol in dataGridView2.Columns)
if (!dgvGridCol.Visible) continue;
iTotalWidth2 += dgvGridCol.Width;
catch (Exception ex)
Error.Log(ex, "Error while printing [OnBeginPrint]");
private void OnPrintPage(object sender, PrintPageEventArgs e)
try
e.Graphics.Clear(Color.White);
var w = e.MarginBounds.Width / cellCount;
var x = e.MarginBounds.X;
var y = e.MarginBounds.Y;
int h;
Rectangle rec;
while (true)
var dgv = !dgv1Finished ? dataGridView1 : dataGridView2;
ColumntWidths = (dgv == dataGridView1) ? arrColumnWidths1 : arrColumnWidths2;
var totalWidths = (dgv == dataGridView1) ? iTotalWidth1 : iTotalWidth2;
var iTmpWidth = 0;
if (pageNumber == 1)
for (int i = dgv.Columns.Count - 1; i >= 0; i--)
DataGridViewColumn GridCol = dgv.Columns[i];
if (!GridCol.Visible) continue;
iTmpWidth = (int)(Math.Floor(GridCol.Width /
(double)totalWidths * totalWidths *
(e.MarginBounds.Width / (double)totalWidths)));
if (!ColumntWidths.Keys.Contains(GridCol.Index))
ColumntWidths.Add(GridCol.Index, iTmpWidth);
using (var sf = new StringFormat())
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
sf.Trimming = StringTrimming.None;
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
// Uncomment to print the headers in the first page only.
//if (pageNumber == 1)
//
h = dgv.RowTemplate.Height + 20;
#region Title
var TextToDraw = dgv.Tag?.ToString();
var xCenter = e.MarginBounds.Left + e.MarginBounds.Width / 2;
e.Graphics.DrawString(TextToDraw, fontD, brushD, xCenter, y - 20, sf);
#endregion
using (var strf = new StringFormat())
strf.Alignment = StringAlignment.Far;
strf.LineAlignment = StringAlignment.Near;
#region Amount
var amount = (dgv == dataGridView1) ? a1800 : a3800;
var XC = e.MarginBounds.Right;
var font = new Font(dgv.Font.FontFamily, 12f, FontStyle.Regular);
e.Graphics.DrawString(amount, font, brushD, XC, y - 20, strf);
#endregion
for (int i = dgv.Columns.Count - 1; i >= 0; i--)
var col = dgv.Columns[i];
if (col.Visible)
w = ColumntWidths[col.Index];
rec = new Rectangle(x, y, w, h);
e.Graphics.FillRectangle(Brushes.AliceBlue, rec);
e.Graphics.DrawString(
col.HeaderText,
col.DataGridView.Font,
Brushes.Black,
rec,
sf);
//Pen pen = new Pen(Color.Black, 1.3f);
//pen.Alignment = PenAlignment.Inset;
//e.Graphics.DrawRectangle(pen, rec);
Color[] colors;
if (false)
colors = new Color[]
SystemColors.ControlDark,
SystemColors.ControlDarkDark,
SystemColors.ControlLightLight,
SystemColors.ControlLight
;
else
colors = new Color[]
SystemColors.ControlLightLight,
SystemColors.ControlLight,
SystemColors.ControlDark,
SystemColors.ControlDarkDark
;
using (Pen p = new Pen(colors[0]))
e.Graphics.DrawLine(p, rec.X, rec.Bottom - 1,
rec.X, rec.Y);
e.Graphics.DrawLine(p, rec.X, rec.Y,
rec.Right - 1, rec.Y);
using (Pen p = new Pen(colors[1]))
e.Graphics.DrawLine(p, rec.X + 1, rec.Bottom - 2,
rec.X + 1, rec.Y + 1);
e.Graphics.DrawLine(p, rec.X + 1, rec.Y + 1,
rec.Right - 2, rec.Y + 1);
using (Pen p = new Pen(colors[2]))
e.Graphics.DrawLine(p, rec.X, rec.Bottom - 1,
rec.Right - 1, rec.Bottom - 1);
e.Graphics.DrawLine(p, rec.Right - 1, rec.Bottom - 1,
rec.Right - 1, rec.Y);
using (Pen p = new Pen(colors[3]))
e.Graphics.DrawLine(p, rec.X + 1, rec.Bottom - 2,
rec.Right - 2, rec.Bottom - 2);
e.Graphics.DrawLine(p, rec.Right - 2, rec.Bottom - 2,
rec.Right - 2, rec.Y + 1);
x += w;
x = e.MarginBounds.X;
y += h;
//
/*Drawing the rows with their content*/
for (var i = rowIndex; i < dgv.RowCount; i++)
var row = dgv.Rows[i];
if (!row.Visible) continue;
if (row.IsNewRow) break;
h = GetRowHeight(e.Graphics, row, e.MarginBounds, sf);
if (h > e.MarginBounds.Height)
MessageBox.Show("Insufficient height.");
e.Cancel = true;
return;
/*Drawing row's cells with their content*/
for (int r = row.Cells.Count - 1; r >= 0; r--)
var cell = row.Cells[r];
if (!cell.Visible) continue;
w = ColumntWidths[cell.ColumnIndex];
rec = new Rectangle(x, y, w, h);
if (rec.Bottom > e.MarginBounds.Bottom)
pageNumber++;
rowIndex = i;
e.HasMorePages = true;
return;
var color = (cell.InheritedStyle.BackColor == Color.Yellow) ? new SolidBrush(SystemColors.Window) : new SolidBrush(cell.InheritedStyle.BackColor);
e.Graphics.FillRectangle(color, rec);
e.Graphics.DrawString(
cell.FormattedValue.ToString(),
dgv.Font,
Brushes.Black,
rec,
sf);
e.Graphics.DrawRectangle(Pens.Black, rec);
x += rec.Width;
/*Done drawing the cells in a row*/
x = e.MarginBounds.X;
y += h;
/*Done drawing all the rows*/
#region Date and time
if (IncludeDateAndTimeInFooter)
var strDate = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString();
var wdate = e.Graphics.MeasureString(strDate, fontD, e.MarginBounds.Height, sf).Width;
var hdate = e.Graphics.MeasureString(strDate, fontD, e.MarginBounds.Height, sf).Height;
var yBottom = e.MarginBounds.Height + e.MarginBounds.Top;
var recDate = new Rectangle(e.MarginBounds.X, yBottom, e.MarginBounds.Width, (int)hdate);
//e.Graphics.FillRectangle(Brushes.LightSkyBlue, recDate);
e.Graphics.DrawRectangle(Pens.Black, recDate);
e.Graphics.DrawString(strDate, fontD, brushD, recDate.X, yBottom);
#endregion
#region Page Number
if (IncludePageNumberInFooter)
var pNumber = "Page " + pageNumber;
var yBottom = e.MarginBounds.Height + e.MarginBounds.Top;
var xRight = e.MarginBounds.Left + (e.MarginBounds.Width - e.Graphics.MeasureString(pNumber, fontD, e.MarginBounds.Width, sf).Width);
e.Graphics.DrawString(pNumber, fontD, brushD, xRight, yBottom);
#endregion
y = y + 70;
rowIndex = 0;
dgv1Finished = true;
e.HasMorePages = (dgv == dataGridView1);
if (!e.HasMorePages)
if (IncludeEndingPhraseAtTheEnd)
using (var strf = new StringFormat())
strf.LineAlignment = StringAlignment.Center;
strf.Alignment = StringAlignment.Center;
strf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
var fontD = new Font(dgv.Font, FontStyle.Bold);
var brushD = Brushes.Black;
var xCenter = e.MarginBounds.Left + e.MarginBounds.Width / 2;
var yBottom = e.MarginBounds.Top
+ e.MarginBounds.Height
+ e.Graphics.MeasureString(EndingPhrase, fontD, e.MarginBounds.Height, strf).Height;
e.Graphics.DrawString(EndingPhrase, fontD, brushD, xCenter, y - 60, strf);
break;
catch (Exception ex)
Error.Log(ex, " Error while printing [OnPrintPage]");
private int GetRowHeight(
Graphics g,
DataGridViewRow row,
Rectangle bounds,
StringFormat sf,
int minHeight = 22)
var cells = row.Cells.OfType<DataGridViewTextBoxCell>()
.Where(c => c.Visible);
if (cells == null) return minHeight;
/*(longest, next) => next.Length > longest.Length ? next : longest*/
var cell = cells.Aggregate((DataGridViewTextBoxCell)null, (x, y) => (x != null) && (!string.IsNullOrWhiteSpace(x.FormattedValue.ToString()) && !string.IsNullOrWhiteSpace(y.FormattedValue.ToString())) &&
(x.FormattedValue.ToString().Length > y.FormattedValue.ToString().Length) ? x : y);
if (cell == null) return minHeight;
var h = g.MeasureString(cell.FormattedValue.ToString(),
row.DataGridView.Font,
new SizeF(ColumntWidths[cell.ColumnIndex], bounds.Height),
sf).ToSize().Height;
return Math.Max(h + 10, minHeight); // 6 for top and bottom margins...
我这样称呼印刷品
var print = new DGVsPrinter(dataGridView1, dataGridView2, printDocument1, Final3800L.Text, Final1800L.Text)
IncludeDateAndTimeInFooter = true,
IncludePageNumberInFooter = true
;
print.Print(true);
【问题讨论】:
@KJ 我试图增加上边距它仍然打印相同的东西但在较低的位置而不是靠近顶部(因为我增加了边距)它就像第一个 datagridview 和上面的数字和文本它不存在。如果我用其他文本打印一个 datagridview,一切都打印得很好。我已经设置了这些边距pageSetupDialog1.PageSettings.Margins = new Margins(50, 100, 40, 70);
@KJ 我发现了问题。如果我通过打印对话框打印它,它打印得很好。但是当我显示预览时,它会出现这个问题。因为我没有在 OnBeginPrint 上将 dgv1Finished 设置为 false。当它实际打印时它再次运行代码并且 dgv1Finished 在预览之后已经是 true 所以它首先获得 datagridview2 而没有关于 datagridvie1 的任何内容。我只需要在 OnBeginPrint 中设置 dgv1Finished = false 就可以打印所有内容了。
【参考方案1】:
我发现了问题。
如果我通过打印对话框打印它,它打印得很好。但是当我显示预览时,就会出现这个问题。因为我在 OnBeginPrint 上没有将 dgv1Finished 设置为 false。
当它实际打印时它再次运行代码,预览后 dgv1Finished 已经为真,因此它首先获取 datagridview2 而对 datagridvie1 没有任何影响。
我只需在 OnBeginPrint 中设置 dgv1Finished = false,现在它会打印所有内容。
【讨论】:
以上是关于WinForms - 打印两个数据网格视图时,打印预览很好,但在纸上只打印第二个 dgv的主要内容,如果未能解决你的问题,请参考以下文章
如果在 vb.net 中有多个页面要打印的数据,如何打印 gridview 内容
将对象列表数据绑定到 WinForms DataGridView,但不显示某些公共属性