📄 exrichtextbox.cs
字号:
using System;
using System.Collections.Specialized;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace Khendys.Controls
{
#region Public Enums
// Enum for possible RTF colors
public enum RtfColor
{
Black, Maroon, Green, Olive, Navy, Purple, Teal, Gray, Silver,
Red, Lime, Yellow, Blue, Fuchsia, Aqua, White
}
#endregion
/// <summary>
/// This class adds the following functionality to RichTextBox:
///
/// 1. Allows plain text to be inserted or appended programmatically to RTF
/// content.
/// 2. Allows the font, text color, and highlight color of plain text to be
/// specified when inserting or appending text as RTF.
/// 3. Allows images to be inserted programmatically, or with interaction from
/// the user.
/// </summary>
/// <remarks>
/// Many solutions to the problem of programmatically inserting images
/// into a RichTextBox use the clipboard or hard code the RTF for
/// the image in the program. This class is an attempt to make the process of
/// inserting images at runtime more flexible without the overhead of maintaining
/// the clipboard or the use of huge, cumbersome strings.
///
/// RTF Specification v1.6 was used and is referred to many times in this document.
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnrtfspec/html/rtfspec.asp
///
/// For information about the RichEdit (Unmanaged RichTextBox) ...
/// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/richedit/richeditcontrols/aboutricheditcontrols.asp
/// </remarks>
public class ExRichTextBox : System.Windows.Forms.RichTextBox
{
#region My Enums
// Specifies the flags/options for the unmanaged call to the GDI+ method
// Metafile.EmfToWmfBits().
private enum EmfToWmfBitsFlags
{
// Use the default conversion
EmfToWmfBitsFlagsDefault = 0x00000000,
// Embedded the source of the EMF metafiel within the resulting WMF
// metafile
EmfToWmfBitsFlagsEmbedEmf = 0x00000001,
// Place a 22-byte header in the resulting WMF file. The header is
// required for the metafile to be considered placeable.
EmfToWmfBitsFlagsIncludePlaceable = 0x00000002,
// Don't simulate clipping by using the XOR operator.
EmfToWmfBitsFlagsNoXORClip = 0x00000004
};
#endregion
#region My Structs
// Definitions for colors in an RTF document
private struct RtfColorDef
{
public const string Black = @"\red0\green0\blue0";
public const string Maroon = @"\red128\green0\blue0";
public const string Green = @"\red0\green128\blue0";
public const string Olive = @"\red128\green128\blue0";
public const string Navy = @"\red0\green0\blue128";
public const string Purple = @"\red128\green0\blue128";
public const string Teal = @"\red0\green128\blue128";
public const string Gray = @"\red128\green128\blue128";
public const string Silver = @"\red192\green192\blue192";
public const string Red = @"\red255\green0\blue0";
public const string Lime = @"\red0\green255\blue0";
public const string Yellow = @"\red255\green255\blue0";
public const string Blue = @"\red0\green0\blue255";
public const string Fuchsia = @"\red255\green0\blue255";
public const string Aqua = @"\red0\green255\blue255";
public const string White = @"\red255\green255\blue255";
}
// Control words for RTF font families
private struct RtfFontFamilyDef
{
public const string Unknown = @"\fnil";
public const string Roman = @"\froman";
public const string Swiss = @"\fswiss";
public const string Modern = @"\fmodern";
public const string Script = @"\fscript";
public const string Decor = @"\fdecor";
public const string Technical = @"\ftech";
public const string BiDirect = @"\fbidi";
}
#endregion
#region My Constants
// Not used in this application. Descriptions can be found with documentation
// of Windows GDI function SetMapMode
private const int MM_TEXT = 1;
private const int MM_LOMETRIC = 2;
private const int MM_HIMETRIC = 3;
private const int MM_LOENGLISH = 4;
private const int MM_HIENGLISH = 5;
private const int MM_TWIPS = 6;
// Ensures that the metafile maintains a 1:1 aspect ratio
private const int MM_ISOTROPIC = 7;
// Allows the x-coordinates and y-coordinates of the metafile to be adjusted
// independently
private const int MM_ANISOTROPIC = 8;
// Represents an unknown font family
private const string FF_UNKNOWN = "UNKNOWN";
// The number of hundredths of millimeters (0.01 mm) in an inch
// For more information, see GetImagePrefix() method.
private const int HMM_PER_INCH = 2540;
// The number of twips in an inch
// For more information, see GetImagePrefix() method.
private const int TWIPS_PER_INCH = 1440;
#endregion
#region My Privates
// The default text color
private RtfColor textColor;
// The default text background color
private RtfColor highlightColor;
// Dictionary that maps color enums to RTF color codes
private HybridDictionary rtfColor;
// Dictionary that mapas Framework font families to RTF font families
private HybridDictionary rtfFontFamily;
// The horizontal resolution at which the control is being displayed
private float xDpi;
// The vertical resolution at which the control is being displayed
private float yDpi;
#endregion
#region Elements required to create an RTF document
/* RTF HEADER
* ----------
*
* \rtf[N] - For text to be considered to be RTF, it must be enclosed in this tag.
* rtf1 is used because the RichTextBox conforms to RTF Specification
* version 1.
* \ansi - The character set.
* \ansicpg[N] - Specifies that unicode characters might be embedded. ansicpg1252
* is the default used by Windows.
* \deff[N] - The default font. \deff0 means the default font is the first font
* found.
* \deflang[N] - The default language. \deflang1033 specifies US English.
* */
private const string RTF_HEADER = @"{\rtf1\ansi\ansicpg1252\deff0\deflang1033";
/* RTF DOCUMENT AREA
* -----------------
*
* \viewkind[N] - The type of view or zoom level. \viewkind4 specifies normal view.
* \uc[N] - The number of bytes corresponding to a Unicode character.
* \pard - Resets to default paragraph properties
* \cf[N] - Foreground color. \cf1 refers to the color at index 1 in
* the color table
* \f[N] - Font number. \f0 refers to the font at index 0 in the font
* table.
* \fs[N] - Font size in half-points.
* */
private const string RTF_DOCUMENT_PRE = @"\viewkind4\uc1\pard\cf1\f0\fs20";
private const string RTF_DOCUMENT_POST = @"\cf0\fs17}";
private string RTF_IMAGE_POST = @"}";
#endregion
#region Accessors
// TODO: This can be ommitted along with RemoveBadCharacters
// Overrides the default implementation of RTF. This is done because the control
// was originally developed to run in an instant messenger that uses the
// Jabber XML-based protocol. The framework would throw an exception when the
// XML contained the null character, so I filtered out.
public new string Rtf
{
get {return RemoveBadChars(base.Rtf);}
set {base.Rtf = value;}
}
// The color of the text
public RtfColor TextColor
{
get {return textColor;}
set {textColor = value;}
}
// The color of the highlight
public RtfColor HiglightColor
{
get {return highlightColor;}
set {highlightColor = value;}
}
#endregion
#region Constructors
/// <summary>
/// Initializes the text colors, creates dictionaries for RTF colors and
/// font families, and stores the horizontal and vertical resolution of
/// the RichTextBox's graphics context.
/// </summary>
public ExRichTextBox() : base()
{
// Initialize default text and background colors
textColor = RtfColor.Black;
highlightColor = RtfColor.White;
// Initialize the dictionary mapping color codes to definitions
rtfColor = new HybridDictionary();
rtfColor.Add(RtfColor.Aqua, RtfColorDef.Aqua);
rtfColor.Add(RtfColor.Black, RtfColorDef.Black);
rtfColor.Add(RtfColor.Blue, RtfColorDef.Blue);
rtfColor.Add(RtfColor.Fuchsia, RtfColorDef.Fuchsia);
rtfColor.Add(RtfColor.Gray, RtfColorDef.Gray);
rtfColor.Add(RtfColor.Green, RtfColorDef.Green);
rtfColor.Add(RtfColor.Lime, RtfColorDef.Lime);
rtfColor.Add(RtfColor.Maroon, RtfColorDef.Maroon);
rtfColor.Add(RtfColor.Navy, RtfColorDef.Navy);
rtfColor.Add(RtfColor.Olive, RtfColorDef.Olive);
rtfColor.Add(RtfColor.Purple, RtfColorDef.Purple);
rtfColor.Add(RtfColor.Red, RtfColorDef.Red);
rtfColor.Add(RtfColor.Silver, RtfColorDef.Silver);
rtfColor.Add(RtfColor.Teal, RtfColorDef.Teal);
rtfColor.Add(RtfColor.White, RtfColorDef.White);
rtfColor.Add(RtfColor.Yellow, RtfColorDef.Yellow);
// Initialize the dictionary mapping default Framework font families to
// RTF font families
rtfFontFamily = new HybridDictionary();
rtfFontFamily.Add(FontFamily.GenericMonospace.Name, RtfFontFamilyDef.Modern);
rtfFontFamily.Add(FontFamily.GenericSansSerif, RtfFontFamilyDef.Swiss);
rtfFontFamily.Add(FontFamily.GenericSerif, RtfFontFamilyDef.Roman);
rtfFontFamily.Add(FF_UNKNOWN, RtfFontFamilyDef.Unknown);
// Get the horizontal and vertical resolutions at which the object is
// being displayed
using(Graphics _graphics = this.CreateGraphics())
{
xDpi = _graphics.DpiX;
yDpi = _graphics.DpiY;
}
}
/// <summary>
/// Calls the default constructor then sets the text color.
/// </summary>
/// <param name="_textColor"></param>
public ExRichTextBox(RtfColor _textColor) : this()
{
textColor = _textColor;
}
/// <summary>
/// Calls the default constructor then sets te text and highlight colors.
/// </summary>
/// <param name="_textColor"></param>
/// <param name="_highlightColor"></param>
public ExRichTextBox(RtfColor _textColor, RtfColor _highlightColor) : this()
{
textColor = _textColor;
highlightColor = _highlightColor;
}
#endregion
#region Append RTF or Text to RichTextBox Contents
/// <summary>
/// Assumes the string passed as a paramter is valid RTF text and attempts
/// to append it as RTF to the content of the control.
/// </summary>
/// <param name="_rtf"></param>
public void AppendRtf(string _rtf)
{
// Move caret to the end of the text
this.Select(this.TextLength, 0);
// Since SelectedRtf is null, this will append the string to the
// end of the existing RTF
this.SelectedRtf = _rtf;
}
/// <summary>
/// Assumes that the string passed as a parameter is valid RTF text and
/// attempts to insert it as RTF into the content of the control.
/// </summary>
/// <remarks>
/// NOTE: The text is inserted wherever the caret is at the time of the call,
/// and if any text is selected, that text is replaced.
/// </remarks>
/// <param name="_rtf"></param>
public void InsertRtf(string _rtf)
{
this.SelectedRtf = _rtf;
}
/// <summary>
/// Appends the text using the current font, text, and highlight colors.
/// </summary>
/// <param name="_text"></param>
public void AppendTextAsRtf(string _text)
{
AppendTextAsRtf(_text, this.Font);
}
/// <summary>
/// Appends the text using the given font, and current text and highlight
/// colors.
/// </summary>
/// <param name="_text"></param>
/// <param name="_font"></param>
public void AppendTextAsRtf(string _text, Font _font)
{
AppendTextAsRtf(_text, _font, textColor);
}
/// <summary>
/// Appends the text using the given font and text color, and the current
/// highlight color.
/// </summary>
/// <param name="_text"></param>
/// <param name="_font"></param>
/// <param name="_color"></param>
public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor)
{
AppendTextAsRtf(_text, _font, _textColor, highlightColor);
}
/// <summary>
/// Appends the text using the given font, text, and highlight colors. Simply
/// moves the caret to the end of the RichTextBox's text and makes a call to
/// insert.
/// </summary>
/// <param name="_text"></param>
/// <param name="_font"></param>
/// <param name="_textColor"></param>
/// <param name="_backColor"></param>
public void AppendTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor)
{
// Move carret to the end of the text
this.Select(this.TextLength, 0);
InsertTextAsRtf(_text, _font, _textColor, _backColor);
}
#endregion
#region Insert Plain Text
/// <summary>
/// Inserts the text using the current font, text, and highlight colors.
/// </summary>
/// <param name="_text"></param>
public void InsertTextAsRtf(string _text)
{
InsertTextAsRtf(_text, this.Font);
}
/// <summary>
/// Inserts the text using the given font, and current text and highlight
/// colors.
/// </summary>
/// <param name="_text"></param>
/// <param name="_font"></param>
public void InsertTextAsRtf(string _text, Font _font)
{
InsertTextAsRtf(_text, _font, textColor);
}
/// <summary>
/// Inserts the text using the given font and text color, and the current
/// highlight color.
/// </summary>
/// <param name="_text"></param>
/// <param name="_font"></param>
/// <param name="_color"></param>
public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor)
{
InsertTextAsRtf(_text, _font, _textColor, highlightColor);
}
/// <summary>
/// Inserts the text using the given font, text, and highlight colors. The
/// text is wrapped in RTF codes so that the specified formatting is kept.
/// You can only assign valid RTF to the RichTextBox.Rtf property, else
/// an exception is thrown. The RTF string should follow this format ...
///
/// {\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{[FONTS]}{\colortbl ;[COLORS]}}
/// \viewkind4\uc1\pard\cf1\f0\fs20 [DOCUMENT AREA] }
///
/// </summary>
/// <remarks>
/// NOTE: The text is inserted wherever the caret is at the time of the call,
/// and if any text is selected, that text is replaced.
/// </remarks>
/// <param name="_text"></param>
/// <param name="_font"></param>
/// <param name="_color"></param>
/// <param name="_color"></param>
public void InsertTextAsRtf(string _text, Font _font, RtfColor _textColor, RtfColor _backColor)
{
StringBuilder _rtf = new StringBuilder();
// Append the RTF header
_rtf.Append(RTF_HEADER);
// Create the font table from the font passed in and append it to the
// RTF string
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -