// Version 2.2
// C#
// Accept control other than a Form
// You can add your own print functions for specific controls and for report title formatting
// Controls can expand
// Expendable TextBox multiline added
// Expandable ListBox added
// Expendable FlexGrid added (Grid from Component One : code in comments only [no references] )
// DataGrid printing
// More comments in source code
// Report printed can continue on many pages
// Can display a trace of controls printed
// Can print page number using your own String.Format
// Report can be print to a multiframe Tif file (example: for faxing)
// Better algorithm to compute extension of container control with rezizable side by side childs
// Test
using System;
using System.Drawing;
using System.Drawing.Printing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Drawing.Imaging;
namespace FormPrinting
{
public class FormPrinting
{
#region "public section"
// publics property that can be changed
public bool TextBoxBoxed = false; // box around TextBox controls
public bool TabControlBoxed = true; // box around TabControl controls
public bool LabelInBold = true; // Print all labels in bold
public bool PrintPreview = true; // enabled Print preview instead of direct printing
public bool DisabledControlsInGray = false; // Color for disabled controls
public bool PageNumbering = false; //If true, reserve space at the bottom of each page and print page number
public string PageNumberingFormat = "Page {0}"; // String format for page number
public OrientationENum Orientation = OrientationENum.Automatic; // choose print orientation (Automatic, Protrait or Landscape)
public ControlPrinting DelegatePrintingReportTitle; // Function that will print report title. Can be changed
//public bool ControlsCanExpand = true; // Indicate if class accept control's expansion
public Single TopMargin = 0; //If 0, use default margin, else use this
public Single BottomMargin = 0; //If 0, use default margin, else use this
public HorizontalAlignment HAlignment = HorizontalAlignment.Center;
public enum OrientationENum
{
Automatic = 1,
Portrait = 2,
Lanscape = 3
}
public enum ParentControlPrinting
{
BeforeChilds = 1,
AfterChilds = 2,
}
// delegate for providing of print function by control type
public delegate void ControlPrinting(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls);
//Constructor
public FormPrinting(System.Windows.Forms.Control f)
{
_f = f;
_TextBoxLikeControl = new ArrayList();
_DelegatesforControls = new ArrayList();
_Pen = new Pen(Color.Black);
// add build-in types and functions
AddTextBoxLikeControl("ComboBox");
AddTextBoxLikeControl("DateTimePicker");
AddTextBoxLikeControl("DateTimeSlicker");
AddTextBoxLikeControl("NumericUpDown");
AddDelegateToPrintControl("TextBox", new ControlPrinting(PrintTextBox));
AddDelegateToPrintControl("System.Windows.Forms.Label", new ControlPrinting(PrintLabel));
AddDelegateToPrintControl("System.Windows.Forms.CheckBox", new ControlPrinting(PrintCheckBox));
AddDelegateToPrintControl("System.Windows.Forms.RadioButton", new ControlPrinting(PrintRadioButton));
AddDelegateToPrintControl("System.Windows.Forms.GroupBox", new ControlPrinting(PrintGroupBox));
AddDelegateToPrintControl("System.Windows.Forms.Panel", new ControlPrinting(PrintPanel));
AddDelegateToPrintControl("System.Windows.Forms.TabControl", new ControlPrinting(PrintTabControl));
AddDelegateToPrintControl("System.Windows.Forms.PictureBox", new ControlPrinting(PrintPictureBox));
AddDelegateToPrintControl("System.Windows.Forms.ListBox", new ControlPrinting(PrintListBox));
AddDelegateToPrintControl("System.Windows.Forms.DataGrid", new ControlPrinting(PrintDataGrid));
}
///
/// Let user add TextBox like control type name
///
/// TextBox like control type name
public void AddTextBoxLikeControl(string stringType)
{
_TextBoxLikeControl.Add(stringType);
}
///
/// Let users provide their own print function for specific control type
///
/// Control type name
/// function (must match with FormPrinting.ControlPrinting delegate)
public void AddDelegateToPrintControl(string stringType, ControlPrinting printFunction)
{
_DelegateforControls d = new _DelegateforControls();
d.typ = stringType;
d.PrintFunction = printFunction;
_DelegatesforControls.Add(d);
}
#endregion
#region "Private data"
// private Font _printFont;
private Pen _Pen;
private Brush _Brush;
private System.Windows.Forms.Control _f;
private ArrayList _TextBoxLikeControl;
private System.Single _xform;
private ArrayList _DelegatesforControls;
private MultiPageManagement _MultiPage;
private System.Text.StringBuilder _traceLog;
private int _indent;
private class _DelegateforControls
{
public string typ;
public ControlPrinting PrintFunction;
}
#endregion
#region "Managing PrintDocument or TIF object"
///
/// Launch printing. Calculate start position and orientation
///
public void Print()
{
try
{
PrintDocument pd = new PrintDocument();
InitPrinting(ref pd);
pd.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);
pd.DocumentName = _f.Text;
if (PrintPreview)
{
PrintPreviewDialog pp = new PrintPreviewDialog();
pp.Document = pd;
pp.WindowState = FormWindowState.Maximized;
pp.ShowDialog();
}
else
{
pd.Print();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public void PrintToTifFile(string fileName)
{
try
{
// Compute bitmap propertiy about same as default printer
PrintDocument pd = new PrintDocument();
InitPrinting(ref pd);
System.Drawing.Bitmap bitmapAllPages, bitmapAdditionnalPage;
bitmapAllPages = new Bitmap(pd.DefaultPageSettings.Bounds.Width, pd.DefaultPageSettings.Bounds.Height);
bitmapAdditionnalPage = new Bitmap(pd.DefaultPageSettings.Bounds.Width, pd.DefaultPageSettings.Bounds.Height);
Graphics g;
//Prepare parameters to save multiframe image
System.Drawing.Imaging.EncoderParameters eps;
eps = new System.Drawing.Imaging.EncoderParameters();
bool firstPage = true;
// Print pages
do
{
if (firstPage)
g = Graphics.FromImage(bitmapAllPages);
else
g = Graphics.FromImage(bitmapAdditionnalPage);
g.Clear(System.Drawing.Color.White);
_MultiPage.NewPage(g);
Single extendedHeight;
Single y;
y = 0;
extendedHeight = 0;
bool scanForChildControls;
if (DelegatePrintingReportTitle == null)
PrintReportTitle(_f, ParentControlPrinting.BeforeChilds , _MultiPage, _xform, y, ref extendedHeight, out scanForChildControls);
else
DelegatePrintingReportTitle(_f, ParentControlPrinting.BeforeChilds , _MultiPage, _xform, y, ref extendedHeight, out scanForChildControls);
y += extendedHeight;
// Print each control on the form
Single globalExtendedHeight;
PrintControls(_f, _MultiPage, _xform, y, out globalExtendedHeight);
if(firstPage)
{
//Create the parameter and choose multi-frame
eps.Param[0]=new EncoderParameter(Encoder.SaveFlag,(long)EncoderValue.MultiFrame);
//Get the correct encoder from the list of available encoders
ImageCodecInfo[] infos=ImageCodecInfo.GetImageEncoders();
int n=0;
while(infos[n].MimeType!="image/tiff")
n++;
//save the first page
bitmapAllPages.Save(fileName + ".tif",infos[n],eps);
}
else
{
//Create the parameter and choose FrameDimensionPage
eps.Param[0]=new EncoderParameter(Encoder.SaveFlag,(long)EncoderValue.FrameDimensionPage);
//save the first page
bitmapAllPages.SaveAdd(bitmapAdditionnalPage,eps);
}
firstPage = false;
} while (!_MultiPage.LastPage());
// Flush pages to file
eps.Param[0]=new EncoderParameter(Encoder.SaveFlag,(long)EncoderValue.Flush);
bitmapAllPages.SaveAdd(eps);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public string GetTrace()
{
return _traceLog.ToString();
}
private void InitPrinting(ref PrintDocument pd)
{
_traceLog = new System.Text.StringBuilder();
_indent = 0;
// Calculate Form position for printing
switch (Orientation)
{
case OrientationENum.Automatic:
if (_f.Size.Width > (pd.DefaultPageSettings.Bounds.Width - pd.DefaultPageSettings.Margins.Right - pd.DefaultPageSettings.Margins.Left))
pd.DefaultPageSettings.Landscape = true;
break;
case OrientationENum.Lanscape:
pd.DefaultPageSettings.Landscape = true;
break;
case OrientationENum.Portrait:
pd.DefaultPageSettings.Landscape = false;
break;
}
// Set page area
Single pageTop = pd.DefaultPageSettings.Margins.Top;
Single pageBottom = pd.DefaultPageSettings.Bounds.Height - pd.DefaultPageSettings.Margins.Bottom;
Single pageLeft = pd.DefaultPageSettings.Margins.Left;
Single pageRight = pd.DefaultPageSettings.Bounds.Width - pd.DefaultPageSettings.Margins.Right;
if (TopMargin != 0)
pageTop = TopMargin;
if (BottomMargin != 0)
pageTop = BottomMargin;
// Calculate left position of print
switch (this.HAlignment)
{
case HorizontalAlignment.Left:
_xform = pageLeft;
break;
case HorizontalAlignment.Center:
_xform = (pd.DefaultPageSettings.Bounds.Width - _f.Size.Width) / 2;
break;
case HorizontalAlignment.Right:
_xform = pageRight - _f.Size.Width;
break;
}
_MultiPage = new MultiPageManagement(pageTop, pageBottom, pageLeft, pageRight, _f.Font, PageNumbering, PageNumberingFormat);
}
///
/// Event handler called by the print document engine. Called for each pages
///
///
///
private void pd_PrintPage(object sender, PrintPageEventArgs ev)
{
_MultiPage.NewPage(ev.Graphics);
Single extendedHeight;
Single y;
y = 0;
extendedHeight = 0;
bool scanForChildControls;
if (DelegatePrintingReportTitle == null)
PrintReportTitle(_f, ParentControlPrinting.BeforeChilds , _MultiPage, _xform, y, ref extendedHeight, out scanForChildControls);
else
DelegatePrintingReportTitle(_f, ParentControlPrinting.BeforeChilds , _MultiPage, _xform, y, ref extendedHeight, out scanForChildControls);
y += extendedHeight;
// Print each control on the form
Single globalExtendedHeight;
PrintControls(_f, _MultiPage, _xform, y, out globalExtendedHeight);
if (_MultiPage.LastPage())
{
ev.HasMorePages = false;
_MultiPage.ResetPage();
}
else
ev.HasMorePages = true;
}
public void PrintReportTitle(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
Font printFont = new Font(c.Font.Name, (Single) (c.Font.Size * 1.3), FontStyle.Bold);
float fontHeight = mp.FontHeight(printFont);
Pen pen = new Pen(Color.Black, 2);
extendedHeight = fontHeight + 3 + pen.Width + 1;
mp.BeginPrintUnit(y, extendedHeight);
//mp.DrawString(c.Text, printFont, Brushes.Black, x, y, c.Width, fontHeight);
y += fontHeight + 3;
//mp.DrawLines(pen, x, y, x + c.Size.Width, y);
mp.EndPrintUnit();
}
#endregion
#region "Recursive printing of controls"
///
/// Print child controls of a "parent" control.
/// Controls are printed from top to bottom.
/// This is the function that calculate position of each control depending of the extension of child controls
///
/// "parent" control
/// printing page object
/// X position of "parent" control
/// Y position of "parent" control
/// necessary height grow of "parent" control to fit with combination of child control growing
public void PrintControls(System.Windows.Forms.Control c,
MultiPageManagement mp,
Single x, Single y,
out Single globalExtendedHeight)
{
int nbCtrl = c.Controls.Count;
Single[] yPos = new Single[nbCtrl];
System.Windows.Forms.Control[] controls = new System.Windows.Forms.Control[nbCtrl];
//Do a list of child controls
for (int i = 0; i < nbCtrl; i++)
{
controls[i] = c.Controls[i];
yPos[i] = c.Controls[i].Location.Y;
}
//Sort them by vertical position
System.Array.Sort(yPos, controls);
//Print them from top to bottom
globalExtendedHeight = 0;
//Single globalextendedYPos = 0;
System.Collections.ArrayList extendedYPos = new System.Collections.ArrayList();
// *****************************************************************
// This loop over child controls calculate position of them.
// Algorithm take care of controls that expand besides and above.
// It keep an arraylist of original and printed (after expansion) bottom
// position of expanded control.
// So control is push down if it was originally below expanded controls
// *****************************************************************
for (int i = 0; i < nbCtrl; i++)
{
// Set y position of control depending of extension of controls above him
Single pushDownHeight = 0;
foreach (Element e in extendedYPos)
if (controls[i].Location.Y >= e.originalBottom) //completely under it
{
if (e.totalPushDown > pushDownHeight)
pushDownHeight = e.totalPushDown;
}
Single cp = controls[i].Location.Y + pushDownHeight;
Single extendedHeight;
PrintControl(controls[i], mp, x + controls[i].Location.X, y + cp, out extendedHeight);
if (extendedHeight > 0)
{
//Keep extention with y position
Element e = new Element();
e.originalBottom = controls[i].Location.Y + controls[i].Height;
e.printedBottom = cp + controls[i].Height + extendedHeight;
extendedYPos.Add(e);
}
}
// same computation for bottom of container control. Its bottom line is
// below all child controls. So it is extended the same as the most pushed
// child control.
globalExtendedHeight = 0;
foreach (Element e in extendedYPos)
if (e.totalPushDown > globalExtendedHeight)
globalExtendedHeight = e.totalPushDown;
}
private class Element
{
public Single originalBottom;
public Single printedBottom;
public Single totalPushDown
{get {return printedBottom - originalBottom;} }
}
///
/// This sub simply use recursivity to print child controls and print
/// the parent control (height may grow depending of child controls).
/// Extension is push up to the previous parent.
///
///
///
///
///
///
public void PrintControl(System.Windows.Forms.Control c,
MultiPageManagement mp,
Single x, Single y,
out Single extendedHeight)
{
extendedHeight = 0;
//if (c.Visible == true)
if(c.Tag != null)
{
bool scanForChildControls;
try
{
// Print my header
PrintOneControl(c, ParentControlPrinting.BeforeChilds, mp, x, y, ref extendedHeight, out scanForChildControls);
// Print Contained controls
if (scanForChildControls)
{
y += extendedHeight;
_indent += 1;
Single ChildControlsExtendedHeight;
PrintControls(c, mp, x, y, out ChildControlsExtendedHeight);
_indent -= 1;
// Print my bottom (habitually a frame arround child controls)
PrintOneControl(c, ParentControlPrinting.AfterChilds, mp, x, y, ref ChildControlsExtendedHeight, out scanForChildControls);
extendedHeight += ChildControlsExtendedHeight;
}
}
catch (Exception ex)
{
MessageBox.Show("Error printing control of type " +
c.GetType().ToString()+
System.Environment.NewLine +
System.Environment.NewLine + ex.ToString());
}
}
}
///
/// Print a control (not is children). Call the print function depending of the type of the control
///
///
///
///
///
///
public void PrintOneControl(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
// Silver color if disable
if (c.Enabled || !DisabledControlsInGray)
{
_Pen = new Pen(Color.Black);
_Brush = Brushes.Black;
}
else
{
_Pen = new Pen(Color.Silver);
_Brush = Brushes.Silver;
}
ScanForChildControls = true;
string s = c.GetType().ToString();
bool founded = false;
//First check if it's a text box like control
if (!founded)
foreach (string sType in _TextBoxLikeControl)
if (s.IndexOf(sType) >= 0)
{
Single h;
h = mp.FontHeight(new Font(c.Font.Name, c.Font.Size));
extendedHeight = mp.BeginPrintUnit(y, h);
PrintText(c, mp, x, y, TextBoxBoxed, false, TextBoxBoxed, HorizontalAlignment.Left);
mp.EndPrintUnit();
founded = true;
ScanForChildControls = false;
break;
}
//Process other type of control, beginning at the end of the list (use last add for a type)
if (!founded)
for (int i = _DelegatesforControls.Count-1; i>=0; i--) // from end to the beginning
{
_DelegateforControls d = (_DelegateforControls) _DelegatesforControls[i];
if (s.EndsWith(d.typ))
{
d.PrintFunction(c, typePrint, mp, x, y, ref extendedHeight, out ScanForChildControls);
break;
}
}
_traceLog.Append(_indent.ToString() + " - " + typePrint.ToString() + " " + s + " (" + c.Text + ":" + c.Name + ") X=" + x.ToString() + " Y=" + y.ToString() + " H=" + c.Height.ToString() + " + " + extendedHeight.ToString()+ System.Environment.NewLine);
}
#endregion
#region "Text printing"
///
/// Print a single line text for many controls. Do some formatting
///
/// Control to print (must have these properties :font, text, width and height)
/// Graphics object (printed page)
/// X position
/// Y position
/// Draw a box arround text
/// use bold font
/// Adjust vertical to obtain precise alignment from different type of control
/// Horizontal alignment of text in control print area
public void PrintText(System.Windows.Forms.Control c,
MultiPageManagement mp,
Single x, Single y,
bool tbBoxed, bool inBold, bool verticalCentering,
HorizontalAlignment hAlignment)
{
Single yAdjusted = y;
//Box
if (tbBoxed)
mp.DrawRectangle(_Pen, x, y, c.Width, c.Height);
//Text
Font printFont;
if (inBold)
printFont = new Font(c.Font.Name, c.Font.Size, FontStyle.Bold);
else
printFont = new Font(c.Font.Name, c.Font.Size);
if (verticalCentering)
{
Single fontHeight = printFont.GetHeight(mp.Graphics());
Single deltaHeight = (c.Height - fontHeight) / 2;
yAdjusted += deltaHeight;
}
else
yAdjusted += 2;
mp.DrawString(c.Text, printFont, _Brush, x, yAdjusted, c.Width, c.Height, BuildFormat(hAlignment));
}
public StringFormat BuildFormat(HorizontalAlignment hAlignment)
{
StringFormat drawFormat = new StringFormat();
switch (hAlignment)
{
case HorizontalAlignment.Left:
drawFormat.Alignment = StringAlignment.Near;
break;
case HorizontalAlignment.Center:
drawFormat.Alignment = StringAlignment.Center;
break;
case HorizontalAlignment.Right:
drawFormat.Alignment = StringAlignment.Far;
break;
}
return drawFormat;
}
public string TrimBlankLines(string s)
{
if (s == null)
return s;
else
{
for (int i = s.Length; i==1; i--)
if ((s[i].ToString() != Keys.Enter.ToString()) && (s[i].ToString() != Keys.LineFeed.ToString()) && (s[i].ToString() != " "))
return s.Substring(0, i);
return s;
}
}
#endregion
#region "Controls printing"
///
/// Print single line or multi lines TextBox.
///
public void PrintTextBox(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
TextBox tb = (System.Windows.Forms.TextBox) c;
Single h = mp.FontHeight(new Font(tb.Font.Name, tb.Font.Size));
if (!tb.Multiline)
{
extendedHeight = mp.BeginPrintUnit(y, h);
PrintText(c, mp, x, y, TextBoxBoxed, tb.Font.Bold, TextBoxBoxed, tb.TextAlign);
mp.EndPrintUnit();
}
else //multiline
{
// cut text into lines that fit in printed textBox width
// Define an area of one line height and call MeasureString on it
// This method return charactersFitted for the line
ArrayList lines = new ArrayList();
System.Drawing.Graphics g = mp.Graphics();
SizeF areaForOneLineOfText = new SizeF();
areaForOneLineOfText.Height = h;
areaForOneLineOfText.Width = tb.Width;
int charactersFitted;
int linesFilled;
int separatorCharPos;
Font printFont = new Font(tb.Font.Name, tb.Font.Size);
int pos = 0;
do
{
g.MeasureString(tb.Text.Substring(pos),
printFont,
areaForOneLineOfText,
new StringFormat(),
out charactersFitted,
out linesFilled);
// this method with one line cut the last word....
// So, I have to go bak in the string to find a separator
// Happyly, MeasureString count separator character in charactersFitted
// For example, return "this is the first line " with space at the end
// even if there is not room for last space
separatorCharPos = charactersFitted;
if (charactersFitted < tb.Text.Substring(pos).Length) //le restant n'entre pas au complet sur la ligne
{
do
{ separatorCharPos --; }
while ((separatorCharPos > pos) && !System.Char.IsSeparator(tb.Text, pos + separatorCharPos));
if (separatorCharPos == pos) // no separator
separatorCharPos = charactersFitted;
else
separatorCharPos ++;
}
lines.Add(tb.Text.Substring(pos, separatorCharPos));
pos += separatorCharPos;
}
while ((pos < tb.Text.Length) && (charactersFitted > 0));
// Print lines one by one
Single yItem = y;
Single extraHeight;
Single extraHeightFirstLine = 0; //Remenber if first line is pull down
for (int i=0; i < lines.Count; i++)
{
extraHeight = mp.BeginPrintUnit(yItem, h); //Space required for tab page caption
if (i == 0)
extraHeightFirstLine = extraHeight;
mp.DrawString((string) lines[i], printFont, _Brush, x, yItem, tb.Width, h);
mp.EndPrintUnit();
yItem += h + extraHeight;
}
if ((yItem - y) > tb.Height)
extendedHeight = (yItem - y) - tb.Height;
if (TextBoxBoxed)
{
_Pen = new Pen(Color.Gray);
//Draw a rectangle arround list box. Start downer if first line pulled down
mp.DrawFrame(_Pen, x, y + extraHeightFirstLine, tb.Width, tb.Height + extendedHeight - extraHeightFirstLine);
}
}
}
public void PrintLabel(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
// Convert ContentAlignment (property of labels) to HorizontalAlignment (Left, center, Right)
HorizontalAlignment ha ;
string ss = c.Text;
ContentAlignment ha2 = ((Label) c).TextAlign;
switch (ha2)
{
case ContentAlignment.BottomLeft:
ha = HorizontalAlignment.Left;
break;
case ContentAlignment.TopLeft:
ha = HorizontalAlignment.Left;
break;
case ContentAlignment.MiddleLeft:
ha = HorizontalAlignment.Left;
break;
case ContentAlignment.BottomCenter:
ha = HorizontalAlignment.Center;
break;
case ContentAlignment.TopCenter:
ha = HorizontalAlignment.Center;
break;
case ContentAlignment.MiddleCenter:
ha = HorizontalAlignment.Center;
break;
case ContentAlignment.BottomRight:
ha = HorizontalAlignment.Right;
break;
case ContentAlignment.TopRight:
ha = HorizontalAlignment.Right;
break;
case ContentAlignment.MiddleRight:
ha = HorizontalAlignment.Right;
break;
default:
ha = HorizontalAlignment.Left;
break;
}
Single h = mp.FontHeight(new Font(c.Font.Name, c.Font.Size));
if (c.Height > h)
h = c.Height;
extendedHeight = mp.BeginPrintUnit(y, h);
PrintText(c, mp, x, y, false, LabelInBold, false, ha);
mp.EndPrintUnit();
}
public void PrintCheckBox(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
Single h = mp.FontHeight(new Font(c.Font.Name, c.Font.Size));
extendedHeight = mp.BeginPrintUnit(y, h);
mp.DrawRectangle(_Pen, x, y, h, h);
if ( ((CheckBox) c).Checked )
{
Single d = 3;
mp.DrawLines(_Pen, x + d, y + d, x + h - d, y + h - d);
PointF[] points2 = new PointF[] {new PointF(x + h - d, y + d), new PointF(x + d, y + h - d)};
mp.DrawLines(_Pen, x + h - d, y + d, x + d, y + h - d);
}
PrintText(c, mp, (float) (x + (h * 1.4)), (float) y - 2, false, false, false, HorizontalAlignment.Left);
mp.EndPrintUnit();
}
public void PrintRadioButton(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
Single h = mp.FontHeight(new Font(c.Font.Name, c.Font.Size));
extendedHeight = mp.BeginPrintUnit(y, h);
mp.DrawEllipse(_Pen, x, y, h, h);
if ( ((RadioButton) c).Checked)
{
Single d = 3;
mp.FillEllipse(_Brush, x + d, y + d, h - d - d, h - d - d);
}
PrintText(c, mp, (float) (x + (h * 1.4)), y - 2, false, false, false, HorizontalAlignment.Left);
mp.EndPrintUnit();
}
public void PrintPanel(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = true;
if (typePrint == ParentControlPrinting.AfterChilds)
if ( ((System.Windows.Forms.Panel) c).BorderStyle != BorderStyle.None)
{
if (((System.Windows.Forms.Panel) c).BorderStyle == BorderStyle.Fixed3D)
_Pen = new Pen(Color.Silver);
// if height less than 10, just print an horizontal line
if ((c.Height < 10) && (c.Controls.Count == 0))
{
extendedHeight += mp.BeginPrintUnit(y, 1);
mp.DrawLines(_Pen, x, y, x + c.Width, y);
mp.EndPrintUnit();
}
else
mp.DrawFrame(_Pen, x, y, c.Width, c.Height + extendedHeight);
}
}
public void PrintGroupBox(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = true;
Font printFont = new Font(c.Font.Name, c.Font.Size);
Single h = mp.FontHeight(printFont);
_Pen = new Pen(Color.Silver);
switch (typePrint)
{
case ParentControlPrinting.BeforeChilds :
// if height less than 10, just print an horizontal line
if ((c.Height < 10) && (c.Controls.Count == 0))
{
extendedHeight += mp.BeginPrintUnit(y, 1);
mp.DrawLines(_Pen, x, y, x + c.Width, y);
mp.EndPrintUnit();
}
else
{
Single extraHeight = mp.BeginPrintUnit(y, h); //Space required for group caption
//PrintText(c, mp, x + h, y, false, true, false, HorizontalAlignment.Left);
mp.DrawString(c.Text, printFont, Brushes.Black, x + h, y, c.Width - h - h, h);
mp.EndPrintUnit();
extendedHeight += extraHeight;
};
break;
case ParentControlPrinting.AfterChilds :
mp.DrawFrame(_Pen, x, y, c.Width, c.Height + extendedHeight);
break;
}
}
public void PrintTabControl(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = true;
System.Windows.Forms.TabControl tc = (TabControl) c;
_Pen = new Pen(Color.Gray);
switch (typePrint)
{
case ParentControlPrinting.BeforeChilds :
//Nom du TabPage
Single extraHeight = mp.BeginPrintUnit(y, tc.ItemSize.Height); //Space required for tab page caption
System.Windows.Forms.TabPage tp = tc.SelectedTab;
Font printFont = new Font(tp.Font.Name, tp.Font.Size, FontStyle.Bold);
Single h = mp.FontHeight(printFont);
if (h > tc.ItemSize.Height)
h = tc.ItemSize.Height;
mp.DrawString(tp.Text, printFont, Brushes.Black, x, y + (tc.ItemSize.Height - h) / 2, tp.Width, h);
mp.DrawLines(_Pen, x, y + tc.ItemSize.Height, x + tc.Width, y + tc.ItemSize.Height);
mp.EndPrintUnit();
extendedHeight += extraHeight;
break;
case ParentControlPrinting.AfterChilds :
if (TabControlBoxed)
mp.DrawFrame(_Pen, x, y, c.Width, c.Height + extendedHeight);
break;
}
}
public void PrintPictureBox(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
extendedHeight = mp.BeginPrintUnit(y, c.Height);
PictureBox pic = (PictureBox) c;
mp.DrawImage(pic.Image, x, y, c.Width, c.Height);
mp.EndPrintUnit();
}
public void PrintListBox(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
ListBox lb = (ListBox) c;
Single yItem = y;
Single extraHeight;
Single extraHeightFirstLine = 0; //Remenber if first line is pull down
Font printFont = new Font(lb.Font.Name, lb.Font.Size, FontStyle.Bold);
int oldPos = lb.SelectedIndex; //save position
for (int i = 0; i < lb.Items.Count; i++)
{
extraHeight = mp.BeginPrintUnit(yItem, lb.ItemHeight); //Space required for tab page caption
if (i == 0)
extraHeightFirstLine = extraHeight;
lb.SelectedIndex = i; // set position to obtain Text of current item
mp.DrawString(lb.Text, printFont, _Brush, x, yItem, lb.Width, lb.ItemHeight);
mp.EndPrintUnit();
yItem += lb.ItemHeight + extraHeight;
}
lb.SelectedIndex = oldPos; //restore position
if ((yItem - y) > lb.Height)
extendedHeight = (yItem - y) - lb.Height;
_Pen = new Pen(Color.Gray);
//Draw a rectangle arround list box. Start downer if first line pulled down
mp.DrawFrame(_Pen, x, y + extraHeightFirstLine, c.Width, c.Height + extendedHeight - extraHeightFirstLine);
}
public void PrintDataGrid(System.Windows.Forms.Control c,
ParentControlPrinting typePrint,
MultiPageManagement mp,
Single x, Single y,
ref Single extendedHeight, out bool ScanForChildControls)
{
ScanForChildControls = false;
DataGrid dg = (DataGrid) c;
Single extraHeight = 0;
Single extraHeightHeaderLine = 0;
Font printFont = new Font(dg.Font.Name, dg.Font.Size, FontStyle.Bold);
Single h = mp.FontHeight(printFont);
// Column header
DataGridTableStyle myGridTableStyle;
if (dg.TableStyles.Count == 0)
{
myGridTableStyle = new DataGridTableStyle();
dg.TableStyles.Add(myGridTableStyle);
}
// Header of each column
Single xPos = x;
Single yPos = y;
Single w;
extraHeightHeaderLine = mp.BeginPrintUnit(yPos, h+1); //Space required for header text
for (int i = 0; i < dg.TableStyles[0].GridColumnStyles.Count; i++)
{
string caption = dg.TableStyles[0].GridColumnStyles[i].HeaderText;
w = dg.TableStyles[0].GridColumnStyles[i].Width;
if (xPos+w > x + dg.Width)
w = x + dg.Width - xPos;
if (xPos < x + dg.Width)
mp.DrawString(caption, printFont, _Brush, xPos, yPos, w, h);
if (i == 0) // Draw horizontal line below header
mp.DrawLines(_Pen, x, yPos+h, x+dg.Width, yPos+h);
xPos += w;
}
mp.EndPrintUnit();
yPos += h + 1 + extraHeightHeaderLine;
// Get dataTable displayed in DataGrid
// This function only support DataGrid with DataTable as DataSource
// This is the only case I code to obtain data in DataGrid
DataTable dt = null;
if (dg.DataSource is System.Data.DataTable)
dt = (DataTable) dg.DataSource;
else
if ((dg.DataSource is System.Data.DataSet) && (dg.DataMember != null))
{
DataSet ds = (DataSet) dg.DataSource;
if (ds.Tables.Contains(dg.DataMember))
dt = ds.Tables[dg.DataMember];
}
// Loop on DataRow, with embed loop on columns
if (dt != null)
foreach (DataRow dr in dt.Rows)
{
extraHeight = mp.BeginPrintUnit(yPos, h); //Space required for header text
xPos = x;
for (int i = 0; i < dg.TableStyles[0].GridColumnStyles.Count; i++)
{
string caption = dr[i].ToString();
w = dg.TableStyles[0].GridColumnStyles[i].Width;
if (xPos+w > x + dg.Width)
w = x + dg.Width - xPos;
if (xPos < x + dg.Width)
mp.DrawString(caption, printFont, _Brush, xPos, yPos, w, h);
xPos += w;
};
mp.EndPrintUnit();
yPos += h + extraHeight;
}
// Draw horizontal line at the bottom of DataGrid
if (yPos < y + dg.Height + extraHeightHeaderLine)
yPos = y + dg.Height + extraHeightHeaderLine;
mp.BeginPrintUnit(yPos, 1);
mp.DrawLines(_Pen, x, yPos, x+dg.Width, yPos);
mp.EndPrintUnit();
// Finally, Compute extendedHeight
if ((yPos - y) > dg.Height)
extendedHeight = (yPos - y) - dg.Height;
}
// public void PrintFlexGrid(System.Windows.Forms.Control c,
// ParentControlPrinting typePrint,
// MultiPageManagement mp,
// Single x, Single y,
// ref Single extendedHeight, out bool ScanForChildControls)
// {
// ScanForChildControls = false;
// C1.Win.C1FlexGrid.C1FlexGrid g = (C1.Win.C1FlexGrid.C1FlexGrid) c;
//
// // print rows and column header (row[0])
// RectangleF r = new RectangleF();
// PointF[] points;
// r.Y = y; //+ r.Height + _Pen.Width ;
// r.Height = g.Font.GetHeight(ev.Graphics);
//
// for (int i = 0; i < g.Rows.Count; i++) // each row
// {
// r.X = x;
// for (int j = 0; j
// {
// r.Width = g.Cols[j].Width;
// if ((r.X + r.Width) > (x + g.Width)) //overtaking
// r.Width = (x + g.Width) - r.X;
// ev.Graphics.DrawString(g.GetDataDisplay(i,j), g.Font, _Brush, r, new StringFormat());
// r.X += r.Width;
// }
// r.Y += r.Height;
// if (i == 0) //Columns header, Add an horizontal line below
// {
// r.Y += 1;
// points = new PointF[] {new PointF(x, r.Y), new PointF(x + g.Width, r.Y)};
// ev.Graphics.DrawLines(_Pen, points);
// r.Y += _Pen.Width ;
// }
// }
//
// // Add a bottom line
// points = new PointF[] {new PointF(x, r.Y), new PointF(x + g.Width, r.Y)};
// ev.Graphics.DrawLines(_Pen, points);
// r.Y += _Pen.Width ;
//
// // Compute extendedHeight
// if (r.Y > y + g.Height)
// extendedHeight = r.Y - (y + g.Height);
// }
// StringFormat _StringFormatFromFlexGridAlign(C1.Win.C1FlexGrid.TextAlignEnum fg)
// {
// StringFormat sf = new StringFormat();
// string s = fg.ToString().ToUpper();
// if (s.IndexOf("LEFT") == 0)
// sf.Alignment = System.Drawing.StringAlignment.Near;
// if (s.IndexOf("RIGHT") == 0)
// sf.Alignment = System.Drawing.StringAlignment.Far;
// if (s.IndexOf("CENTER") == 0)
// sf.Alignment = System.Drawing.StringAlignment.Center;
// return sf;
// }
#endregion
#region "Multi page class"
public class MultiPageManagement
{
private bool _PageOverflow;
private Single _realPageTop, _realPageHeight, _UsablePageHeight;
private Single _realPageLeft, _realPageRight;
private Single _CurrentPageTop, _CurrentPageBottom;
private int _PageNumber = 0;
//private PrintPageEventArgs _Ev;
private Graphics _G;
private bool _PrintUnit;
private bool _PrintInCurrentPage;
private Single _PrintUnitPullDown;
private bool _pageNumbering;
private Font _FontForPageNumering;
private string _PageNumberingFormat;
public System.Drawing.Graphics Graphics()
{
return _G;
}
// Constructor
public MultiPageManagement(Single pageTop, Single pageBottom, Single pageLeft, Single pageRight, Font formFont, bool pageNumbering, string pageNumberingFormat)
{
_realPageTop = pageTop;
_realPageHeight = pageBottom - pageTop;
_realPageLeft = pageLeft;
_realPageRight = pageRight;
_pageNumbering = pageNumbering;
if (_pageNumbering)
{
_PageNumberingFormat = pageNumberingFormat;
_FontForPageNumering = new Font(formFont.Name, (Single) (formFont.Size * 0.8));
}
}
///
/// Check if items printed below current page
///
///
public bool LastPage()
{
return (! _PageOverflow);
}
///
/// Change page. Reset page properties
///
/// Graphics object
public void NewPage(Graphics g)
{
_G = g;
_PageNumber += 1;
_UsablePageHeight = _realPageHeight;
if (_pageNumbering)
{
Single fontHeightForPageNumbering = FontHeight(_FontForPageNumering);
_UsablePageHeight -= (Single) (fontHeightForPageNumbering * 1.5);
// Compute rectangular space for page number
RectangleF _recForPageNumbering = new RectangleF();
_recForPageNumbering.X = _realPageLeft;
_recForPageNumbering.Y = _realPageTop + _realPageHeight - fontHeightForPageNumbering;
_recForPageNumbering.Width = _realPageRight - _realPageLeft;
_recForPageNumbering.Height = fontHeightForPageNumbering;
// impression
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Far;
_G.DrawString(String.Format(_PageNumberingFormat, _PageNumber), _FontForPageNumering, Brushes.Black, _recForPageNumbering, drawFormat);
}
_CurrentPageTop = _UsablePageHeight * (_PageNumber - 1);
_CurrentPageBottom = _CurrentPageTop + _UsablePageHeight;
_PageOverflow = false;
}
public void ResetPage()
{
_PageNumber = 0;
}
public Single BeginPrintUnit(Single y, Single neededHeight)
{
if (neededHeight > _UsablePageHeight)
throw new Exception("Needed height cannot exceed 1 page. Page height = " + _UsablePageHeight);
_PrintUnit = true;
// Verify if unit goes accross a page break
// if it's the case, calculate vertical push down height to place the
// top of unit just below page break
Single pageBreakPos;
Single printingPos = y;
for (pageBreakPos = _UsablePageHeight; pageBreakPos < (y + neededHeight); pageBreakPos += _UsablePageHeight)
if( (y <= pageBreakPos) && ((y + neededHeight - 1) > pageBreakPos) ) //Accross
printingPos = pageBreakPos;
_PrintUnitPullDown = printingPos - y;
// test if unit is in current page else if another page is needed
_PrintInCurrentPage = false;
if (printingPos + neededHeight - 1 > _CurrentPageBottom)
_PageOverflow = true;
else
if (printingPos >= _CurrentPageTop)
_PrintInCurrentPage = true;
return _PrintUnitPullDown;
}
private Single _ConvertToPage(Single y)
{
Single newY = y - _CurrentPageTop + _realPageTop;
if (_PrintUnit)
return newY += _PrintUnitPullDown;
return newY;
}
public void EndPrintUnit()
{
_PrintUnit = false;
}
private bool PrintUnitIsInCurrentPage()
{
if (!_PrintUnit)
throw new Exception("Must be in a print unit to print");
return _PrintInCurrentPage;
}
public Single FontHeight(Font font)
{
return font.GetHeight(_G);
}
public void DrawLines(Pen pen, Single x1, Single y1, Single x2, Single y2)
{
if (PrintUnitIsInCurrentPage())
{
Single y1page = _ConvertToPage(y1);
Single y2page = _ConvertToPage(y2);
PointF[] points = new PointF[2];
points[0].X = x1;
points[0].Y = y1page;
points[1].X = x2;
points[1].Y = y2page;
_G.DrawLines(pen, points);
}
}
public void DrawString(string s, Font printFont, Brush brush, Single x, Single y, Single w, Single h)
{
DrawString(s, printFont, brush, x, y, w, h, new StringFormat());
}
public void DrawString(string s, Font printFont, Brush brush, Single x, Single y, Single w, Single h, StringFormat sf)
{
if (PrintUnitIsInCurrentPage())
{
Single yPage = _ConvertToPage(y);
RectangleF r = new RectangleF();
r.X = x;
r.Y = yPage;
r.Width = w;
r.Height = h;
_G.DrawString(s, printFont, brush, r, sf);
}
}
public void DrawRectangle(Pen pen, Single x, Single y, Single w, Single h)
{
if (PrintUnitIsInCurrentPage())
{
Single yPage = _ConvertToPage(y);
_G.DrawRectangle(pen, x, yPage, w, h);
}
}
public void DrawEllipse(Pen pen, Single x, Single y, Single w, Single h)
{
if (PrintUnitIsInCurrentPage())
{
Single yPage = _ConvertToPage(y);
_G.DrawEllipse(pen, x, yPage, w, h);
}
}
public void FillEllipse(Brush brush, Single x, Single y, Single w, Single h)
{
if (PrintUnitIsInCurrentPage())
{
Single yPage = _ConvertToPage(y);
_G.FillEllipse(brush, x, yPage, w, h);
}
}
public void DrawImage(Image image, Single x, Single y, Single w, Single h)
{
if (PrintUnitIsInCurrentPage())
{
Single yPage = _ConvertToPage(y);
_G.DrawImage(image, x, yPage, w, h);
}
}
public void DrawFrame(Pen pen, Single x, Single y, Single w, Single h)
{
PointF[] points = new PointF[2];
Single yTop = _CurrentPageTop;
Single yBottom = _CurrentPageBottom;
if (y+h <= _CurrentPageTop ) //Bottom of Frame above current page
return;
if (y >= _CurrentPageBottom) //Top of Frame below current page
{
_PageOverflow = true;
return;
}
// Assign X coordinate for horizontal lines
points[0].X = x;
points[1].X = x + w;
// Draw top line
if (y >= _CurrentPageTop) //Top in current page
{
yTop = y;
points[0].Y = _ConvertToPage(yTop);
points[1].Y = _ConvertToPage(yTop);
_G.DrawLines(pen, points);
}
// Draw bottom line
if (y+h <= _CurrentPageBottom) //Bottom in current page
{
yBottom = y+h;
points[0].Y = _ConvertToPage(yBottom);
points[1].Y = _ConvertToPage(yBottom);
_G.DrawLines(pen, points);
}
else
_PageOverflow = true;
// Assign Y coordinate for vertical lines
points[0].Y = _ConvertToPage(yTop);
points[1].Y = _ConvertToPage(yBottom);
// Draw left line
points[0].X = x;
points[1].X = x;
_G.DrawLines(pen, points);
// Draw right line
points[0].X = x + w;
points[1].X = x + w;
_G.DrawLines(pen, points);
}
}
#endregion
}
}