How To: Printing Form Controls in C# and .NET

The other day a user asked me how to print out a form.  I suggested they use my Form Capture article which catches the bitmap that the form is in by using bit belting commands from the old windows SDK.  It turns out this is not the ideal solution because it involves old Windows SDK code.  A better solution would be to draw the controls individually onto the printing graphics object.  But how the heck do I print a control?  Do I have to actually copy Microsoft Controls bit by bit?  Do I have to mimic the shading and 3d features by drawing different lines that produce shading effects?
 
 
Figure 1 - A Form and the Print Preview of the same Form
 
It turns out that Microsoft provides the user with a helpful class that allows us to draw these elusive controls called ControlPaint.  This class is more like an API containing a list of static methods to help you paint the controls.  Below I listed the ones used in this article and their purpose:
 
Method in ControlPaint Description
DrawButton Draws a Button in the Graphics area.  Note this command will not draw any text or image on the button 
DrawCheckBox Draws a Checkbox in the Graphics area 
DrawBorder3D This will allow you to draw any 3D Border Side.  
Table 1 - Methods of ControlPaint used in this article
 
As we have discussed in previous printing articles on C# Corner, printing and drawing are accomplished almost the same way, by writing to a device context, or in the case of .NET, to a Graphics Object.  We are not going to go into detail on how to set up the printing components for calling the method that paints the controls to the printer.  Please refer to Printing in C# on the site to see how to set up the Print_Page event handler.
 
Our event handler for printing the form will call a method called, ironically, DrawForm, and perform all of the control painting here. Below is the method DrawForm in our Form class:
 
Listing 1 - Draw the Form and controls to the printer Graphics object 
  1. void DrawForm(Graphics g, int resX, int resY) {  
  2.  g.FillRectangle(new SolidBrush(this.BackColor), 0, 0, this.Width, this.Height);  
  3.  float scale = resX / ScreenResolution;  
  4.  // Cycle through each control on the form and paint it to the printe  
  5.  foreach(Control c in Controls) {  
  6.   // Get the time of the next control so we can unbox it  
  7.   string strType = c.GetType().ToString().Substring(c.GetType().ToString().LastIndexOf(".") + 1);  
  8.   switch (strType) {  
  9.    case "Button":  
  10.     Button b = (Button) c;  
  11.     // Use the ControlPaint method DrawButton in order to draw the button of the form  
  12.     ControlPaint.DrawButton(g, ((Button) c).Left, ((Button) c).Top, ((Button) c).Width, ((Button) c).Height, ButtonState.Normal);  
  13.     // We also need to draw the text  
  14.     g.DrawString(b.Text, b.Font, new SolidBrush(b.ForeColor), b.Left + b.Width / 2 - g.MeasureString(b.Text,  
  15.      b.Font).Width / 2, b.Top + b.Height / 2 - g.MeasureString("a", b.Font).Height / 2, new StringFormat());  
  16.     break;  
  17.    case "TextBox":  
  18.     TextBox t = (TextBox) c;  
  19.     // Draw a text box by drawing a pushed in button and filling the rectangle with the background color and the text  
  20.     // of the TextBox control  
  21.     // First the sunken border  
  22.     ControlPaint.DrawButton(g, t.Left, t.Top, t.Width, t.Height, ButtonState.Pushed);  
  23.     // Then fill it with the background of the textbox  
  24.     g.FillRectangle(new SolidBrush(t.BackColor), t.Left + 1, t.Top + 1, t.Width + 2, t.Height - 2);  
  25.     // Finally draw the string inside  
  26.     g.DrawString(t.Text, t.Font, new SolidBrush(t.ForeColor), t.Left + 2, t.Top + t.Height / 2 - g.MeasureString("a", t.Font).Height / 2, new StringFormat());  
  27.     break;  
  28.    case "CheckBox"// We have a checkbox to paint, unbox it  
  29.     CheckBox cb = (CheckBox) c;  
  30.     // Use the DrawCheckBox command to draw a checkbox and pass the button state to paint it checked or unchecked  
  31.     if (cb.Checked)  
  32.      ControlPaint.DrawCheckBox(g, cb.Left, cb.Top, cb.Height / 2, cb.Height / 2, ButtonState.Checked);  
  33.     else  
  34.      ControlPaint.DrawCheckBox(g, cb.Left, cb.Top, cb.Height / 2, cb.Height / 2, ButtonState.Normal);  
  35.     // Don't forget the checkbox text  
  36.     g.DrawString(cb.Text, cb.Font, new SolidBrush(cb.ForeColor), cb.Right - cb.Height - g.MeasureString(cb.Text, cb.Font).Width, cb.Top, new StringFormat());  
  37.     break;  
  38.   }  
  39.  }  
  40. }  
The code above cycles through each control in the form and paints the control to the Graphics object.  The code takes advantage of the ControlPaint methods we mentioned above.  The DrawButton method is used to paint both the 3D button controls and the 3D text boxes.  The DrawCheckBox method of the ControlPaint class is used to draw the 3D checkbox.  In every case we need to draw the text separately from the control using the DrawString method of the Graphics Object.  We also needed to fill in the TextBox background with the FillRectangle method in the Graphics object.
 
Conclusion
 
Much more code can be added to this project to handle radio buttons, listviews, listboxes, and comboboxes.  The ControlPaint class contains  methods that can help you to paint other Window Form controls such as DrawScrollButton, DrawRadioButton, DrawGrid, DrawComboButton and DrawFocusRectangle.  If your form only contains edit boxes, checkboxes, and buttons, then this code may cover the bulk of your work.


Similar Articles