You can print the content of your RuchTextBox
by sending a EM_FORMATRANGE
message to it.
This message is typically used to format the content of rich edit
control for an output device such as a printer.
To implement this solution, you can do these steps:
- First create a
RichtextBoxEx
class that inherits from RichTextBox
and implement a FormatRange
method that its job is to print each page of your control contents. The complete code is listed below.
- Then Create a
Form
and put a RichTextBoxEx
, PrintDocument
on it and handle BeginPrint
, PrintPage
and EndPrint
events of PrintDocument
and use following codes to perform print.
Please note
Using this way, you can print the content of your control with all of formatting applied to text, that is better than printing all text in a black color with one font and size. Also you can set the font and size of content to be in one font and size and color.
Creating RichtextBoxEx
is just for encapsulation and is completely optional and if you want to use your existing control, simply you can use content of FormatRange
method that I provided below and pass properties of your control to it to perform print.
RichTextBoxEx that supports Printing:
Here is the complete working code of what I described above. The code is extracted from the msdn article Getting WYSIWYG Print Results from a .NET RichTextBox article by Martin Müller.
public class RichTextBoxEx : RichTextBox
{
[StructLayout(LayoutKind.Sequential)]
private struct STRUCT_RECT
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
[StructLayout(LayoutKind.Sequential)]
private struct STRUCT_CHARRANGE
{
public Int32 cpMin;
public Int32 cpMax;
}
[StructLayout(LayoutKind.Sequential)]
private struct STRUCT_FORMATRANGE
{
public IntPtr hdc;
public IntPtr hdcTarget;
public STRUCT_RECT rc;
public STRUCT_RECT rcPage;
public STRUCT_CHARRANGE chrg;
}
[DllImport("user32.dll")]
private static extern Int32 SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, IntPtr lParam);
private const Int32 WM_USER = 0x400;
private const Int32 EM_FORMATRANGE = WM_USER + 57;
private const Int32 EM_GETCHARFORMAT = WM_USER + 58;
private const Int32 EM_SETCHARFORMAT = WM_USER + 68;
/// <summary>
/// Calculate or render the contents of our RichTextBox for printing
/// </summary>
/// <param name="measureOnly">If true, only the calculation is performed, otherwise the text is rendered as well</param>
/// <param name="e">The PrintPageEventArgs object from the PrintPage event</param>
/// <param name="charFrom">Index of first character to be printed</param>
/// <param name="charTo">Index of last character to be printed</param>
/// <returns> (Index of last character that fitted on the page) + 1</returns>
public int FormatRange(bool measureOnly, PrintPageEventArgs e, int charFrom, int charTo)
{
// Specify which characters to print
STRUCT_CHARRANGE cr = default(STRUCT_CHARRANGE);
cr.cpMin = charFrom;
cr.cpMax = charTo;
// Specify the area inside page margins
STRUCT_RECT rc = default(STRUCT_RECT);
rc.top = HundredthInchToTwips(e.MarginBounds.Top);
rc.bottom = HundredthInchToTwips(e.MarginBounds.Bottom);
rc.left = HundredthInchToTwips(e.MarginBounds.Left);
rc.right = HundredthInchToTwips(e.MarginBounds.Right);
// Specify the page area
STRUCT_RECT rcPage = default(STRUCT_RECT);
rcPage.top = HundredthInchToTwips(e.PageBounds.Top);
rcPage.bottom = HundredthInchToTwips(e.PageBounds.Bottom);
rcPage.left = HundredthInchToTwips(e.PageBounds.Left);
rcPage.right = HundredthInchToTwips(e.PageBounds.Right);
// Get device context of output device
IntPtr hdc = default(IntPtr);
hdc = e.Graphics.GetHdc();
// Fill in the FORMATRANGE structure
STRUCT_FORMATRANGE fr = default(STRUCT_FORMATRANGE);
fr.chrg = cr;
fr.hdc = hdc;
fr.hdcTarget = hdc;
fr.rc = rc;
fr.rcPage = rcPage;
// Non-Zero wParam means render, Zero means measure
Int32 wParam = default(Int32);
if (measureOnly)
{
wParam = 0;
}
else
{
wParam = 1;
}
// Allocate memory for the FORMATRANGE struct and
// copy the contents of our struct to this memory
IntPtr lParam = default(IntPtr);
lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fr));
Marshal.StructureToPtr(fr, lParam, false);
// Send the actual Win32 message
int res = 0;
res = SendMessage(Handle, EM_FORMATRANGE, wParam, lParam);
// Free allocated memory
Marshal.FreeCoTaskMem(lParam);
// and release the device context
e.Graphics.ReleaseHdc(hdc);
return res;
}
/// <summary>
/// Convert between 1/100 inch (unit used by the .NET framework)
/// and twips (1/1440 inch, used by Win32 API calls)
/// </summary>
/// <param name="n">Value in 1/100 inch</param>
/// <returns>Value in twips</returns>
private Int32 HundredthInchToTwips(int n)
{
return Convert.ToInt32(n * 14.4);
}
/// <summary>
/// Free cached data from rich edit control after printing
/// </summary>
public void FormatRangeDone()
{
IntPtr lParam = new IntPtr(0);
SendMessage(Handle, EM_FORMATRANGE, 0, lParam);
}
}
Example of Usage:
private void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
// Start at the beginning of the text
firstCharOnPage = 0;
}
private void printDocument1_EndPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
{
// Clean up cached information
richTextBoxEx1.FormatRangeDone();
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
firstCharOnPage = richTextBoxEx1.FormatRange(false, e, firstCharOnPage, richTextBoxEx1.TextLength);
// check if there are more pages to print
if (firstCharOnPage < richTextBoxEx1.TextLength)
e.HasMorePages = true;
else
e.HasMorePages = false;
}
private void printToolStripButton_Click(object sender, EventArgs e)
{
//Print the contents here
printDocument1.Print();
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…