none
How do I set the RichTextBox.SelectionFont FontFamily without changing the Style?

    Question

  • One of the controls in my application limits a user to be able to change only the font style (B, I, U) and colour of the text.  I have created a custom control which inherits from the RichTextBox for this purpose.  I am able to intercept CTRL-V, and set the font of the pasted text to SystemFonts.DefaultFont.  The problem I am currently facing is if the pasted text contains, for example, half bold half regular style - the bold is lost.

    i.e.  'FooBar' will just paste as 'FooBar'.

    My only idea currently is to go through the text character by character (**VERY** slow), and do something like:

        public class MyRichTextBox : RichTextBox
        {
        private RichTextBox hiddenBuffer = new RichTextBox();
        /// <summary>
        /// This paste will strip the font size, family and alignment from the text being pasted.
        /// </summary>
        public void PasteUnformatted()
        {
            this.hiddenBuffer.Clear();
            this.hiddenBuffer.Paste();
            for (int x = 0; x < this.hiddenBuffer.TextLength; x++)
            {
                // select the next character
                this.hiddenBuffer.Select(x, 1);
                // Set the font family and size to default
                this.hiddenBuffer.SelectionFont = new Font(SystemFonts.DefaultFont.FontFamily, SystemFonts.DefaultFont.Size, this.hiddenBuffer.SelectionFont.Style);
            }
            // Reset the alignment
            this.hiddenBuffer.SelectionAlignment = HorizontalAlignment.Left;
            base.SelectedRtf = this.hiddenBuffer.SelectedRtf;
            this.hiddenBuffer.Clear();
        }
    }

    Can anyone think of a cleaner (and faster) solution?

    Wednesday, October 28, 2009 1:24 PM

Answers

  • Yes, the native RichEdit control supports this with the EM_SETCHARFORMAT message.  This code worked well:

    using System.Runtime.InteropServices;
    ...
            public static bool SetRtbFace(RichTextBox rtb, Font font, bool selectionOnly) {
                CHARFORMATW fmt = new CHARFORMATW();
                fmt.cbSize = Marshal.SizeOf(fmt);
                fmt.szFaceName = font.FontFamily.Name;
                fmt.dwMask = 0x20000000;  // CFM_FACE
                return IntPtr.Zero != SendMessage(rtb.Handle, 0x444, (IntPtr)(selectionOnly ? 1 : 4), fmt);
            }
            [StructLayout(LayoutKind.Sequential, Pack = 4)]
            private class CHARFORMATW {
                public int cbSize;
                public int dwMask;
                public int dwEffects;
                public int yHeight;
                public int yOffset;
                public int crTextColor;
                public byte bCharSet;
                public byte bPitchAndFamily;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)]
                public string szFaceName;
            }

            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, CHARFORMATW lParam);


    Hans Passant.
    • Marked as answer by Philip W Wednesday, October 28, 2009 3:36 PM
    Wednesday, October 28, 2009 3:10 PM

All replies

  • Yes, the native RichEdit control supports this with the EM_SETCHARFORMAT message.  This code worked well:

    using System.Runtime.InteropServices;
    ...
            public static bool SetRtbFace(RichTextBox rtb, Font font, bool selectionOnly) {
                CHARFORMATW fmt = new CHARFORMATW();
                fmt.cbSize = Marshal.SizeOf(fmt);
                fmt.szFaceName = font.FontFamily.Name;
                fmt.dwMask = 0x20000000;  // CFM_FACE
                return IntPtr.Zero != SendMessage(rtb.Handle, 0x444, (IntPtr)(selectionOnly ? 1 : 4), fmt);
            }
            [StructLayout(LayoutKind.Sequential, Pack = 4)]
            private class CHARFORMATW {
                public int cbSize;
                public int dwMask;
                public int dwEffects;
                public int yHeight;
                public int yOffset;
                public int crTextColor;
                public byte bCharSet;
                public byte bPitchAndFamily;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)]
                public string szFaceName;
            }

            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, CHARFORMATW lParam);


    Hans Passant.
    • Marked as answer by Philip W Wednesday, October 28, 2009 3:36 PM
    Wednesday, October 28, 2009 3:10 PM
  • Yes, the native RichEdit control supports this with the EM_SETCHARFORMAT message.  This code worked well:

    using System.Runtime.InteropServices;
    ...
            public static bool SetRtbFace(RichTextBox rtb, Font font, bool selectionOnly) {
                CHARFORMATW fmt = new CHARFORMATW();
                fmt.cbSize = Marshal.SizeOf(fmt);
                fmt.szFaceName = font.FontFamily.Name;
                fmt.dwMask = 0x20000000;  // CFM_FACE
                return IntPtr.Zero != SendMessage(rtb.Handle, 0x444, (IntPtr)(selectionOnly ? 1 : 4), fmt);
            }
            [StructLayout(LayoutKind.Sequential, Pack = 4)]
            private class CHARFORMATW {
                public int cbSize;
                public int dwMask;
                public int dwEffects;
                public int yHeight;
                public int yOffset;
                public int crTextColor;
                public byte bCharSet;
                public byte bPitchAndFamily;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)]
                public string szFaceName;
            }

            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, CHARFORMATW lParam);


    Hans Passant.

    It works!  Thank you so much...
    Wednesday, October 28, 2009 3:36 PM