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. "Foo Bar" will just paste as "Foo Bar".

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?

Was it helpful?

Solution

'nobugz' over on the MSDN Forums answered this for me (I needed an answer quickly, so after almost a day of tumbleweed from SO, I had to look elsewhere - don't judge me!):

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);

OTHER TIPS

For those wanting a Delphi answer, an extract to give you the basic idea:

using RichEdit; //reqd. for the constants and types

var
  chformat : TCharFormat2;
  fontname : string;

begin
  FillChar(chformat,sizeof(chformat),0);
  chformat.cbSize := sizeof(chformat);
  //only modify the szFaceName field, height etc. left alone
  chformat.dwMask :=  CFM_FACE; 
  //get the fontname set by the user
  fontname := AdvFontSelector1.Text;
  strpcopy(chformat.szFaceName,fontname);
  RichEdit1.Perform(EM_SETCHARFORMAT, SCF_SELECTION, lparam(@chformat));
end;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top