title: PrintPage PrintPageEventHandler Is Printing Too Many Copies
body: <p>I have to print shipping labels for the products our company manufactures.</p>
  
  <p>To help give myself a feel for how these labels will turn out, I design them using a Windows Form. This allows me to position my text, get the fonts set right, etc. using <code>Label</code> controls, add a custom <code>BarCode</code> control, and get "<em>fancy</em>" with <code>Panel</code> controls to group items into boxes.</p>
  
  <p>Each page holds two (2) labels.</p>
  
  <p>When my code prints a label document, I request either 2, 4 or 6 copies. Occasionally, the Print Preview is used as well. In this case, I have to reset the number of labels created.</p>
  
  <p>However, when the documents print:</p>
  
  <ul>
  <li>if the request is for 2 copies, the code prints 2 sheets of paper (4 labels)</li>
  <li>if the request is for 4 copies, the code prints 8 sheets of paper (16 labels)</li>
  <li>if the request is for 6 copies, the code prints a whopping 18 pages (36 labels)</li>
  </ul>
  
  <p>Does anyone see a pattern? I do not.</p>
  
  <p>This is my Print command:</p>
  
  <pre><code>public int Print(string docName, int rows, int columns, int copies) {
    short shortCopies = (short)copies;
    LabelsHorizontal = rows;
    LabelsVertical = columns;
    Size docSize = PrintPreview.Document.DefaultPageSettings.Bounds.Size;
    float height = 0.8F * Screen.PrimaryScreen.WorkingArea.Size.Height;
    float width = (height * docSize.Width) / docSize.Height;
    Size winSize = new Size((int)width, (int)height);
    PrintPreview.Height = winSize.Height;
    PrintPreview.Width = winSize.Width;
    if (!String.IsNullOrEmpty(docName)) {
      PrintPreview.Document.DocumentName = docName;
    }
    PrintPreview.Document.PrinterSettings.Copies = shortCopies;
    PrintPreview.SettingsFilename = Settings.PageSettingsLocation;
    if (!PrintPreview.PrinterSelected) {
      if (PrintPreview.ShowPrinterSelectDialog() != DialogResult.OK) {
        return 0;
      }
    }
    labelQtyPrinted = 0;
    if (ShowPrintPreview) {
      PrintPreview.ShowDialog();
    } else {
      PrintPreview.PrintDocument();
    }
    return labelQtyPrinted;
  }
  // Resets the Label Count between PrintPreview and Print
  private void PrintPreview_OnPrintClicked(object sender, EventArgs e) {
    labelQtyPrinted = 0;
  }
  </code></pre>
  
  <p>I had to write a custom PrintPreview class that takes the <code>PrintPreviewDialog</code> as a base class so that I could override its Print button with this <strong>printButton_Click</strong> method:</p>
  
  <pre><code>// Handles the Printing of the Document
  internal void printButton_Click(object sender, EventArgs e) {
    if (OnPrintClicked != null) {
      OnPrintClicked(sender, e); // this resets my labelQtyPrinted value shown above
    }
    Document.Print();
    printed = true;
    Close();
  }
  </code></pre>
  
  <p>In the <code>Print</code> method (the first snippet of code), <code>PrintPreview.PrintDocument()</code> is just code that calls the <code>printButton_Click</code> event.</p>
  
  <p>My <strong>PrintPageEventHandler</strong> is shown below:</p>
  
  <pre><code>private void Document_Printed(object sender, PrintPageEventArgs e) {
    if (PrintPreview.Document.PrinterSettings.Copies &lt;= labelQtyPrinted) {
      throw new Exception("Run Away Printer");
    }
    float scale;
    SizeF pageSize = new SizeF(
      PrintPreview.Document.DefaultPageSettings.PaperSize.Width,
      PrintPreview.Document.DefaultPageSettings.PaperSize.Height
    );
    Margins m = PrintPreview.Document.DefaultPageSettings.Margins;
    float printableHeight = pageSize.Height - (m.Top + m.Bottom);
    float printableWidth = pageSize.Width - (m.Left + m.Right);
    if (printableWidth &lt; printableHeight) {
      if (labelSize.Width &lt; labelSize.Height) {
        float r1 = (printableWidth) / labelSize.Width;
        float r2 = (printableHeight) / labelSize.Height;
        scale = (r1 &lt; r2) ? r1 : r2;
      } else {
        scale = (printableWidth) / labelSize.Width;
      }
    } else {
      if (labelSize.Width &lt; labelSize.Height) {
        scale = (printableHeight) / labelSize.Height;
      } else {
        float r1 = (printableWidth) / labelSize.Width;
        float r2 = (printableHeight) / labelSize.Height;
        scale = (r1 &lt; r2) ? r1 : r2;
      }
    }
    float lh = scale * labelSize.Height;
    float lw = scale * labelSize.Width;
    float ml = scale * m.Left;
    float mt = scale * m.Top;
    Graphics G = e.Graphics;
    G.SmoothingMode = smoothMode;
    G.TextRenderingHint = TextRenderingHint.AntiAlias;
    for (int i = 0; i &lt; LabelsHorizontal; i++) {
      float dx = i * (lw + ml); // Horizontal shift * scale
      for (int j = 0; j &lt; LabelsVertical; j++) {
        float dy = j * (lh + mt); // Vertical shift * scale
        #region ' Panels '
        foreach (Panel item in panels) {
          float h = scale * item.Size.Height;
          float w = scale * item.Size.Width;
          float x = (ml + dx) + scale * item.Location.X;
          float y = (mt + dy) + scale * item.Location.Y;
          using (SolidBrush b = new SolidBrush(item.BackColor)) {
            G.FillRectangle(b, x, y, w, h);
          }
          using (Pen p = new Pen(Brushes.Black)) {
            G.DrawRectangle(p, x, y, w, h);
          }
        }
        #endregion
        #region ' Logo '
        if (logo != null) {
          float h = scale * logo.Height;
          float w = scale * logo.Width;
          float x = (ml + dx) + scale * logoPt.X;
          float y = (mt + dy) + scale * logoPt.Y;
          G.DrawImage(logo, x, y, w, h);
        }
        #endregion
        #region ' Labels '
        foreach (Label item in labels) {
          float h = scale * item.Size.Height;
          float w = scale * item.Size.Width;
          float x = (ml + dx) + scale * item.Location.X;
          float y = (mt + dy) + scale * item.Location.Y;
          Color c = PrintPreview.Document.DefaultPageSettings.Color ? item.ForeColor : Color.Black;
          Font font = new Font(item.Font.FontFamily, scale * item.Font.Size, item.Font.Style);
          using (SolidBrush b = new SolidBrush(c)) {
            StringFormat format = GetStringFormatFromContentAllignment(item.TextAlign);
            format.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
            format.Trimming = StringTrimming.None;
            PointF locationF = new PointF(x, y);
            SizeF size = new SizeF(w, h);
            RectangleF r = new RectangleF(locationF, size);
            G.DrawString(item.Text, font, b, r, format);
          }
        }
        #endregion
        #region ' Barcodes '
        foreach (AcpBarcodeControl item in barcodes) {
          Image img = item.GetBarcodeImage(item.BarcodeText);
          if (img != null) {
            float h = scale * item.Size.Height;
            float w = scale * item.Size.Width;
            float x = (ml + dx) + scale * item.Location.X;
            float y = (mt + dy) + scale * item.Location.Y;
            G.DrawImage(img, x, y, w, h);
          }
        }
        #endregion
        labelQtyPrinted++;
        if (labelQtyPrinted == PrintPreview.Document.PrinterSettings.Copies) {
          e.HasMorePages = false;
          return;
        }
      }
      e.HasMorePages = (labelQtyPrinted &lt; PrintPreview.Document.PrinterSettings.Copies);
    }
  }
  </code></pre>
  
  <p>All in all, it works very well. The <strong>"Run Away Printer"</strong> Exception is never thrown.</p>
  
  <p>So, why are so many copies being made?</p>
  
  <p>The Printer is an HP LaserJet 4050, if that makes any difference.</p>