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,但不显示某些公共属性

如何在 ASP.NET MVC 视图中用 C# 打印出 GridView?

UWP 打印预览仅在第一页显示空白页

将打印媒体的引导网格从 col-xs 更改为 col-sm

从数据网格视图和数据库中删除选定的行