Reset RTF formatting in a WinForms RichTextBox without discarding its text?
Asked Answered
I

10

20

I'm trying to "reset" the formatting in my RichTextBox (WinForms, not WPF). I was previously using

richTextBox.Text = richTextBox.Text;

However, that seems to have suddenly failed me. Now no matter what I set richTextBox.Text to, it retains some of the rtf formatting.

I've tried

richTextBox.Rtf = richTextBox.Text;

However, that complains about an incorrect format. There's gotta be a better way to do this. (Of course, selecting the entire thing, then resetting the back color, fore color, and font works, but that results in a flicker as the entire thing is selected then deselected, plus it's slower and requires a lot more code.) Anyone have any idea?

Edit: I've gotten this to work:

string tempTxt = richTextBox.Text;
richTextBox.Clear();
richTextBox.Text = tempTxt;

But there has to be a better way, right?

Edit 2: To be clear, I wish to remove all formatting while retaining the text. It looks like the code in the first edit will ship, unless anyone else has a more efficient/better coding way.

Edit 3:

richTextBox.Text = richTextBox.Text.ToString();

doesn't seem to work because it still doesn't clear all the formatting. The reason I don't like the method in the first Edit above is it makes the text box "flash" when it clears it then re-inputs the text. It seems like there should simply be a richTextBox.ResetFormatting() method, or some way to access the same functionality, as the Clear() method clearly (no pun intended) does some sort of formatting reset in addition to simply clearing all the text.

To summarize:

Is there a way (and if so, what is it) to reset the formatting of the text in a RichTextBox without clearing the text as in the example above (because that produces undesirable flashing)?

Irisirisa answered 12/8, 2009 at 18:49 Comment(0)
L
28

Saddly I've done my VERY best effort to slim this down to only the required code. It's still big, but it will work. The RichTextBox api in .Net is very limited, to do anything you almost have to thunk into the Win32 library. I've built a entire library around this thing just so I can toggle bold and determine if bold is actually set across the selection.

Usage:

RichTextBox te = ...;
te.ClearAllFormatting(new Font("Microsoft Sans Serif", 8.25f));

Tons of code:

static class RichTextExtensions
{
    public static void ClearAllFormatting(this RichTextBox te, Font font)
    {
        CHARFORMAT2 fmt = new CHARFORMAT2();

        fmt.cbSize = Marshal.SizeOf(fmt);
        fmt.dwMask = CFM_ALL2;
        fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
        fmt.szFaceName = font.FontFamily.Name;

        double size = font.Size;
        size /= 72;//logical dpi (pixels per inch)
        size *= 1440.0;//twips per inch

        fmt.yHeight = (int)size;//165
        fmt.yOffset = 0;
        fmt.crTextColor = 0;
        fmt.bCharSet = 1;// DEFAULT_CHARSET;
        fmt.bPitchAndFamily = 0;// DEFAULT_PITCH;
        fmt.wWeight = 400;// FW_NORMAL;
        fmt.sSpacing = 0;
        fmt.crBackColor = 0;
        //fmt.lcid = ???
        fmt.dwMask &= ~CFM_LCID;//don't know how to get this...
        fmt.dwReserved = 0;
        fmt.sStyle = 0;
        fmt.wKerning = 0;
        fmt.bUnderlineType = 0;
        fmt.bAnimation = 0;
        fmt.bRevAuthor = 0;
        fmt.bReserved1 = 0;

        SendMessage(te.Handle, EM_SETCHARFORMAT, SCF_ALL, ref fmt);
    }

    private const UInt32 WM_USER = 0x0400;
    private const UInt32 EM_GETCHARFORMAT = (WM_USER + 58);
    private const UInt32 EM_SETCHARFORMAT = (WM_USER + 68);
    private const UInt32 SCF_ALL = 0x0004;
    private const UInt32 SCF_SELECTION = 0x0001;

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, UInt32 wParam, ref CHARFORMAT2 lParam);

    [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
    struct CHARFORMAT2
    {
        public int cbSize;
        public uint dwMask;
        public uint dwEffects;
        public int yHeight;
        public int yOffset;
        public int crTextColor;
        public byte bCharSet;
        public byte bPitchAndFamily;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
        public string szFaceName;
        public short wWeight;
        public short sSpacing;
        public int crBackColor;
        public int lcid;
        public int dwReserved;
        public short sStyle;
        public short wKerning;
        public byte bUnderlineType;
        public byte bAnimation;
        public byte bRevAuthor;
        public byte bReserved1;
    }

    #region CFE_
    // CHARFORMAT effects 
    const UInt32 CFE_BOLD = 0x0001;
    const UInt32 CFE_ITALIC = 0x0002;
    const UInt32 CFE_UNDERLINE = 0x0004;
    const UInt32 CFE_STRIKEOUT = 0x0008;
    const UInt32 CFE_PROTECTED = 0x0010;
    const UInt32 CFE_LINK = 0x0020;
    const UInt32 CFE_AUTOCOLOR = 0x40000000;            // NOTE: this corresponds to 
    // CFM_COLOR, which controls it 
    // Masks and effects defined for CHARFORMAT2 -- an (*) indicates
    // that the data is stored by RichEdit 2.0/3.0, but not displayed
    const UInt32 CFE_SMALLCAPS = CFM_SMALLCAPS;
    const UInt32 CFE_ALLCAPS = CFM_ALLCAPS;
    const UInt32 CFE_HIDDEN = CFM_HIDDEN;
    const UInt32 CFE_OUTLINE = CFM_OUTLINE;
    const UInt32 CFE_SHADOW = CFM_SHADOW;
    const UInt32 CFE_EMBOSS = CFM_EMBOSS;
    const UInt32 CFE_IMPRINT = CFM_IMPRINT;
    const UInt32 CFE_DISABLED = CFM_DISABLED;
    const UInt32 CFE_REVISED = CFM_REVISED;

    // CFE_AUTOCOLOR and CFE_AUTOBACKCOLOR correspond to CFM_COLOR and
    // CFM_BACKCOLOR, respectively, which control them
    const UInt32 CFE_AUTOBACKCOLOR = CFM_BACKCOLOR;
    #endregion
    #region CFM_
    // CHARFORMAT masks 
    const UInt32 CFM_BOLD = 0x00000001;
    const UInt32 CFM_ITALIC = 0x00000002;
    const UInt32 CFM_UNDERLINE = 0x00000004;
    const UInt32 CFM_STRIKEOUT = 0x00000008;
    const UInt32 CFM_PROTECTED = 0x00000010;
    const UInt32 CFM_LINK = 0x00000020;         // Exchange hyperlink extension 
    const UInt32 CFM_SIZE = 0x80000000;
    const UInt32 CFM_COLOR = 0x40000000;
    const UInt32 CFM_FACE = 0x20000000;
    const UInt32 CFM_OFFSET = 0x10000000;
    const UInt32 CFM_CHARSET = 0x08000000;

    const UInt32 CFM_SMALLCAPS = 0x0040;            // (*)  
    const UInt32 CFM_ALLCAPS = 0x0080;          // Displayed by 3.0 
    const UInt32 CFM_HIDDEN = 0x0100;           // Hidden by 3.0 
    const UInt32 CFM_OUTLINE = 0x0200;          // (*)  
    const UInt32 CFM_SHADOW = 0x0400;           // (*)  
    const UInt32 CFM_EMBOSS = 0x0800;           // (*)  
    const UInt32 CFM_IMPRINT = 0x1000;          // (*)  
    const UInt32 CFM_DISABLED = 0x2000;
    const UInt32 CFM_REVISED = 0x4000;

    const UInt32 CFM_BACKCOLOR = 0x04000000;
    const UInt32 CFM_LCID = 0x02000000;
    const UInt32 CFM_UNDERLINETYPE = 0x00800000;        // Many displayed by 3.0 
    const UInt32 CFM_WEIGHT = 0x00400000;
    const UInt32 CFM_SPACING = 0x00200000;      // Displayed by 3.0 
    const UInt32 CFM_KERNING = 0x00100000;      // (*)  
    const UInt32 CFM_STYLE = 0x00080000;        // (*)  
    const UInt32 CFM_ANIMATION = 0x00040000;        // (*)  
    const UInt32 CFM_REVAUTHOR = 0x00008000;

    const UInt32 CFE_SUBSCRIPT = 0x00010000;        // Superscript and subscript are 
    const UInt32 CFE_SUPERSCRIPT = 0x00020000;      //  mutually exclusive           

    const UInt32 CFM_SUBSCRIPT = (CFE_SUBSCRIPT | CFE_SUPERSCRIPT);
    const UInt32 CFM_SUPERSCRIPT = CFM_SUBSCRIPT;

    // CHARFORMAT "ALL" masks
    const UInt32 CFM_EFFECTS = (CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_COLOR |
                         CFM_STRIKEOUT | CFE_PROTECTED | CFM_LINK);
    const UInt32 CFM_ALL = (CFM_EFFECTS | CFM_SIZE | CFM_FACE | CFM_OFFSET | CFM_CHARSET);

    const UInt32 CFM_EFFECTS2 = (CFM_EFFECTS | CFM_DISABLED | CFM_SMALLCAPS | CFM_ALLCAPS
                        | CFM_HIDDEN | CFM_OUTLINE | CFM_SHADOW | CFM_EMBOSS
                        | CFM_IMPRINT | CFM_DISABLED | CFM_REVISED
                        | CFM_SUBSCRIPT | CFM_SUPERSCRIPT | CFM_BACKCOLOR);

    const UInt32 CFM_ALL2 = (CFM_ALL | CFM_EFFECTS2 | CFM_BACKCOLOR | CFM_LCID
                        | CFM_UNDERLINETYPE | CFM_WEIGHT | CFM_REVAUTHOR
                        | CFM_SPACING | CFM_KERNING | CFM_STYLE | CFM_ANIMATION);
    #endregion
}

More you ask?

I use most of this via a small utility class that wraps this for all the styles and font changes. This way you can change font-size and not change font name, etc.

class RichTextStyle
{   
    private readonly Control _textEdit;
    private readonly CHARFORMAT2 _charFormat;

    public RichTextStyle(RichTextBox te)
    {
        _textEdit = te;
        _charFormat = new CHARFORMAT2();
        _charFormat.cbSize = Marshal.SizeOf(_charFormat);
        SendMessage(te.Handle, EM_GETCHARFORMAT, SCF_SELECTION, ref _charFormat);
    }

    private void SetEffect(UInt32 mask, UInt32 effect, bool valid)
    {
        CHARFORMAT2 fmt = new CHARFORMAT2();
        fmt.cbSize = Marshal.SizeOf(fmt);
        fmt.dwMask = mask;
        fmt.dwEffects = valid ? effect : 0;
        SendMessage(_textEdit.Handle, EM_SETCHARFORMAT, SCF_SELECTION, ref fmt);
    }

    private bool GetEffect(UInt32 mask, UInt32 effect)
    {
        return (0 != (_charFormat.dwMask & mask)) && (0 != (_charFormat.dwEffects & effect));
    }

    public bool Bold { get { return GetEffect(CFM_BOLD, CFE_BOLD); } set { SetEffect(CFM_BOLD, CFE_BOLD, value); } }
    public bool Italic { get { return GetEffect(CFM_ITALIC, CFE_ITALIC); } set { SetEffect(CFM_ITALIC, CFE_ITALIC, value); } }

    // ... etc ... etc ... you get the idea.
Litigious answered 14/10, 2009 at 0:41 Comment(12)
...wow. That is awesome! Thank you. I'll test this as soon as I can. Have you released this code under a license, or can we just freely incorporate it into our code?Irisirisa
Anything on stackoverflow is licensed by the creative commons license found here: creativecommons.org/licenses/by-sa/2.5/legalcodeLitigious
BTW, I accept the Up vote and accepted answer as as payment in full :)Litigious
So if I interpret the license correctly, I cannot use this code in a commercial application?Irisirisa
You can also check the meta site for a better answer, or post a question if you don't find one: meta.stackoverflow.comLitigious
This seems to work well, except for one problem: it seems to disable the ability to use the code richTextBox.SelectionFont = new Font(richTextBox.SelectionFont, FontStyle.Underline); to underline the selected text. Was this an intended feature? Is there a way around it?Irisirisa
I also tried using the RichTextStyle class to underline...it also failed.Irisirisa
I'm going to mark this as the answer, as it definitely works well. However, it looks like I won't be able to use it because underlining is not working. (Bold works fine...?)Irisirisa
Ah, I figured it out. The line "fmt.bUnderlineType = 0;" should read "fmt.bUnderlineType = 1;". This will tell it to use normal underlining, while not actually underlining anything. Setting it to zero said to not do anything even when I told it to underline. Well, now that that's fixed, I'm happy to say this code works perfectly. Thank you SO MUCH!Irisirisa
Thanks for letting me know about the underline thing. Apparently I never tried that, DOH!Litigious
FYI: This is not resetting "paragraph" settings -- bullets/numbering, left/right/indent offsets, before/after spacing and single/double/etc. line spacing.Heavensent
This sets the font color to black. To set another color, remove the CFE_AUTOCOLOR flag and change fmt.crTextColor = 0 to fmt.crTextColor = R | (G << 8) | (B << 16) where r, g, b are your desired color bytes.Cotten
A
6

What about

richTextBox.Text = richTextBox.Text.ToString();
Aceldama answered 25/9, 2009 at 22:50 Comment(4)
Ack, we've done some more testing, and this doesn't quite work for us. It seems Clear() does something that this does not. Sorry!Irisirisa
-1 why would Text.ToString() be any different than Text which the OP already tried?Litigious
At the time it seemed that the tostring() method stripped the formatting, sorry for trying to helpAceldama
I didn't think that worked however it worked for me. it's a best answer and very short dirty solution. thanks so much @Mike B.Schoenburg
G
3

I have used

var t = richTextBox1.Text;
richTextBox1.Text = t; 

EDIT::

be sure to insert a comment as to why you're doing what you're doing. To the unaware, it looks ridiculous.

Gorgeous answered 12/10, 2009 at 22:22 Comment(1)
Wait, so does the use of "var" make it think you're giving it different text? Because just richTextBox.Text = richTextBox.Text or = richTextBox.Text.ToString() or using a string doesn't work because internally it checks to see if the strings are different before going any further.Irisirisa
E
2

Just using:

richTextBox1.Clear();

... Should do the trick. Works for me.

Europe answered 16/8, 2009 at 18:44 Comment(1)
For me that clears all the text -- I need the text to still be there, without the formatting. I'm currently using .Clear() in conjunction with a temporary string, as seen in the edit above.Irisirisa
I
1

Another way I've found (and the one that I have switched to using, as it doesn't flash) is to grab the initial rtf string before any formatting is applied:

string initialRtf = richTextBox.Rtf;

Then, when I want to reset the formatting, I can just do:

richTextBox.Rtf = initialRtf;

However, this isn't really perfect, because it requires that the text stay the same and such. Well, at least it's a little better than the method detailed in the question.

Irisirisa answered 12/10, 2009 at 22:14 Comment(0)
M
1

"The reason I don't like the method in the first Edit above is it makes the text box "flash" when it clears it then re-inputs the text."

You should be able to implement the SuspendLayout() and ResumeLayout() methods.

string tempTxt = richTextBox.Text;
rtbIncludes.SuspendLayout();
richTextBox.Clear();
richTextBox.Text = tempTxt;
rtbIncludes.ResumeLayout();

SuspendLayout() and ResumeLayout() will stop the control from drawing while you manipulate the data. If the operation doesn't take to long, you will be able to clear the text and assign the unformatted text back without it appearing to flash on the screen.

If it does take too long, the control will appear as a black rectangle until ResumeLayout() is called.

Music answered 12/9, 2013 at 20:3 Comment(0)
S
1

For a while, I've been using this code in my own program. It sets the RTF of the RichTextBox directly, so should be much faster than setting styles the usual way. It takes in a string (the main text), and optionally also takes a Color array, font size array (int), and font-weight array (bool), each which represents every colour, size or font-weight for every character in the string.

Alternatively, you can simply keep the default size, weight, italic numbers given by the header.

public string text2RTF(string text, Color[] color = null, bool[] bold = null, int[] size = null,
                        string font = "Microsoft Sans Serif", double defaultFontSize = 16,
                        bool defaultFontBold = false, bool defaultFontItalic = false, char align = 'l')
{
    StringBuilder rtf = new StringBuilder();
    rtf.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang2057{\fonttbl{\f0\fnil\fcharset0 ");
    rtf.Append(font);
    rtf.Append(@";}}{\colortbl ;");

    if (color != null)
    {
        rtf.Append("\\red" + (color[0].R).ToString() + "\\green" + (color[0].G).ToString() + "\\blue" + (color[0].B).ToString() + ";");
        for (int i = 1; i < text.Length; i++)
        {
            if ((color[i].R != color[i - 1].R || color[i].G != color[i - 1].G || color[i].B != color[i - 1].B))
            {
                rtf.Append("\\red" + (color[i].R).ToString() + "\\green" + (color[i].G).ToString() + "\\blue" + (color[i].B).ToString() + ";");
            }
        }
    }


    rtf.Append("}\n\\viewkind4\\uc1\\pard");
    if (defaultFontBold == true) rtf.Append("\\b");
    if (defaultFontItalic == true) rtf.Append("\\i");

    if (align == 'r')   rtf.Append("\\qr");

    rtf.Append("\\f0\\fs" + (Math.Round(defaultFontSize)).ToString()+" ");
    int startOfActualText = rtf.Length;

    int count = 1;
    for (int i = 0; i < text.Length; i++)
    {
        if (color!=null && (i == 0 || color[i].R != color[i - 1].R || color[i].G != color[i - 1].G || color[i].B != color[i - 1].B))
        {
            rtf.Append("\\cf"); rtf.Append(count.ToString() + " "); count++;
        }
        if (bold!=null && (i == 0 || bold[i] != bold[i - 1]))
        {
            if (bold[i] == true) rtf.Append("\\b1 ");
            else rtf.Append("\\b0 ");
        }
        if (size!=null && (i == 0 || size[i] != size[i - 1]))
        {
            rtf.Append("\\fs"+size[i].ToString()+" " );                 
        }

        if (text[i] == '\\' || text[i] == '}' || text[i] == '{') rtf.Append('\\');

        // GetRtfUnicodeOfChar:
        string st="";
        if (text[i] <= 0x7f) st = text[i].ToString();
        else st = "\\u" + Convert.ToUInt32(text[i]) + "?";


        rtf.Append(st);
    }

    rtf.Append("\n}");
    rtf.Replace("\n", "\\par\n", startOfActualText, rtf.Length - startOfActualText);


    return rtf.ToString();

}
Sniffy answered 22/4, 2015 at 1:18 Comment(2)
Is the input text also in RTF format being parsed in the for loop? Can you add some usage examples? Thanks for this code!Brewster
@osstekz: The input text string will just be plain English text,. The code will automatically convert the plain text to RTF.Sniffy
A
1

I see that there are many answers, but I think that there is more simple and easy approach as the extension to clear all the formatting:

In my case I needed clear the formatting and leave an empty RichTextBox, therefore I made this function:

private void ClearRichTextBox()
{
  this.richTextBox1.ForeColor = Color.Empty;
  this.richTextBox1.BackColor = Color.Empty;
  this.richTextBox1.SelectAll();
  this.richTextBox1.SelectionColor = Color.Empty;
  this.richTextBox1.SelectionBackColor = Color.Empty;
  this.richTextBox1.SelectionFont = this.richTextBox1.Font;
  this.richTextBox1.Clear();
}

Then the easy solution is:

string backUp = this.richTextBox1.Text;
ClearRichTextBox();
this.richTextBox1.Text = backUp;

Or simply remove the this.richTextBox1.Clear(); line in the clear function. (This will probably also work but I give no guarantee since I tested this only on simple formattings. Therefore it can be, that any other line should be added to remove a different formatting.)

When the text should be not cleared remember to store previous position/selection and refresh state after deformatting of data.

Assize answered 20/5, 2015 at 9:34 Comment(0)
D
-1
RichTextBox rtbTemp = new RichTextBox();
rtbTemp.Text = rtb.Text;
rtb.Rtf = rtbTemp.Rtf;

hope it works

Diatonic answered 15/10, 2009 at 15:11 Comment(0)
C
-1

works fine ..

var TempString = richTextBox1.Text;
richTextBox1.Rtf = string.Empty;
richTextBox1.Text = TempString ;
Coplanar answered 2/9, 2016 at 14:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.