using System; using System.Windows.Forms; using System.Runtime.InteropServices; /// /// Represents a standard with some /// minor added functionality. /// /// /// AdvRichTextBox provides methods to maintain performance /// while it is being updated. Additional formatting features /// have also been added. /// namespace CSharpFormLibrary { public class AdvRichTextBox : RichTextBox { /// /// Maintains performance while updating. /// /// /// /// It is recommended to call this method before doing /// any major updates that you do not wish the user to /// see. Remember to call EndUpdate when you are finished /// with the update. Nested calls are supported. /// /// /// Calling this method will prevent redrawing. It will /// also setup the event mask of the underlying richedit /// control so that no events are sent. /// /// public void BeginUpdate() { // Deal with nested calls. ++updating; if (updating > 1) return; // Prevent the control from raising any events. oldEventMask = SendMessage(new HandleRef(this, Handle), EM_SETEVENTMASK, 0, 0); // Prevent the control from redrawing itself. SendMessage(new HandleRef(this, Handle), WM_SETREDRAW, 0, 0); } /// /// Resumes drawing and event handling. /// /// /// This method should be called every time a call is made /// made to BeginUpdate. It resets the event mask to it's /// original value and enables redrawing of the control. /// public void EndUpdate() { // Deal with nested calls. --updating; if (updating > 0) return; // Allow the control to redraw itself. SendMessage(new HandleRef(this, Handle), WM_SETREDRAW, 1, 0); // Allow the control to raise event messages. SendMessage(new HandleRef(this, Handle), EM_SETEVENTMASK, 0, oldEventMask); } /// /// Gets or sets the alignment to apply to the current /// selection or insertion point. /// /// /// Replaces the SelectionAlignment from /// . /// public new TextAlign SelectionAlignment { get { PARAFORMAT fmt = new PARAFORMAT(); fmt.cbSize = Marshal.SizeOf(fmt); // Get the alignment. SendMessage(new HandleRef(this, Handle), EM_GETPARAFORMAT, SCF_SELECTION, ref fmt); // Default to Left align. if ((fmt.dwMask & PFM_ALIGNMENT) == 0) return TextAlign.Left; return (TextAlign)fmt.wAlignment; } set { PARAFORMAT fmt = new PARAFORMAT(); fmt.cbSize = Marshal.SizeOf(fmt); fmt.dwMask = PFM_ALIGNMENT; fmt.wAlignment = (short)value; // Set the alignment. SendMessage(new HandleRef(this, Handle), EM_SETPARAFORMAT, SCF_SELECTION, ref fmt); } } /// /// This member overrides /// .OnHandleCreated. /// protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); // Enable support for justification. SendMessage(new HandleRef(this, Handle), EM_SETTYPOGRAPHYOPTIONS, TO_ADVANCEDTYPOGRAPHY, TO_ADVANCEDTYPOGRAPHY); } private int updating = 0; private int oldEventMask = 0; // Constants from the Platform SDK. private const int EM_SETEVENTMASK = 1073; private const int EM_GETPARAFORMAT = 1085; private const int EM_SETPARAFORMAT = 1095; private const int EM_SETTYPOGRAPHYOPTIONS = 1226; private const int WM_SETREDRAW = 11; private const int TO_ADVANCEDTYPOGRAPHY = 1; private const int PFM_ALIGNMENT = 8; private const int SCF_SELECTION = 1; // It makes no difference if we use PARAFORMAT or // PARAFORMAT2 here, so I have opted for PARAFORMAT2. [StructLayout(LayoutKind.Sequential)] private struct PARAFORMAT { public int cbSize; public uint dwMask; public short wNumbering; public short wReserved; public int dxStartIndent; public int dxRightIndent; public int dxOffset; public short wAlignment; public short cTabCount; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public int[] rgxTabs; // PARAFORMAT2 from here onwards. public int dySpaceBefore; public int dySpaceAfter; public int dyLineSpacing; public short sStyle; public byte bLineSpacingRule; public byte bOutlineLevel; public short wShadingWeight; public short wShadingStyle; public short wNumberingStart; public short wNumberingStyle; public short wNumberingTab; public short wBorderSpace; public short wBorderWidth; public short wBorders; } [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, int lParam); [DllImport("user32", CharSet = CharSet.Auto)] private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, ref PARAFORMAT lp); } /// /// Specifies how text in a is /// horizontally aligned. /// public enum TextAlign { /// /// The text is aligned to the left. /// Left = 1, /// /// The text is aligned to the right. /// Right = 2, /// /// The text is aligned in the center. /// Center = 3, /// /// The text is justified. /// Justify = 4 } }