How do I maintain RichText formatting (bold/italic/etc) when changing any one element?
.net, c#, richtextbox, winforms
Solution
RTB does not support this well. You cannot even discover the range of characters within the selection that has the same font style. Start by checking the SelectionFont property first, it will be null if the selection contains a mix of styles. If that's the case, you'll have to iterate the selection one character at a time by setting the SelectionStart and SelectionLength properties, read the SelectionFont until it changes. Apply the changed font to the range you discovered.
Check this answer for a way to keep this reasonably quick and flicker-free.
Note that implementing an editor with RTB is a favorite topic at codeproject.com. Borrowing code, if not the entire project, is a good way to lessen the pain.
Problem
I have a rich text box that may contain a string that has elements of bold, italics, or even different fonts and sizes. If I select the entire string, including all of the differences, how can I "Bold" that string without converting the entire string to the generic font with just a "bold" attribute? For example: I want to turn "This is some `text`" into "This is some `text`" Note that "is some" remained italicized and "text" remained a different font. What I currently have is quite simplistic: ``` private void tsBold_Click(object sender, EventArgs e) { if (rtb.SelectionFont == null) return; Font f; if (tsBold.Checked) f = new Font(rtb.SelectionFont, FontStyle.Bold); else f = new Font(rtb.SelectionFont, FontStyle.Regular); rtb.SelectionFont = f; rtb.Focus(); } ``` Of course, this is going to apply the exact same font to the entire selection. Is there any way to just append "bold" to the existing font(s)? ANSWER While the "official" answer below is just the tip of the iceberg, it was the push I needed in the right direction. Thank you for the tip. Here's my official fix: I added this to my RichTextBox object: ``` /// <summary> /// Change the richtextbox style for the current selection /// </summary> public void ChangeFontStyle(FontStyle style, bool add) { //This method should handle cases that occur when multiple fonts/styles are selected // Parameters:- // style - eg FontStyle.Bold // add - IF true then add else remove // throw error if style isn't: bold, italic, strikeout or underline if (style != FontStyle.Bold && style != FontStyle.Italic && style != FontStyle.Strikeout && style != FontStyle.Underline) throw new System.InvalidProgramException("Invalid style parameter to ChangeFontStyle"); int rtb1start = this.SelectionStart; int len = this.SelectionLength; int rtbTempStart = 0; //if len <= 1 and there is a selection font then just handle and return if (len <= 1 && this.SelectionFont != null) { //add or remove style if (add) this.SelectionFont = new Font(this.SelectionFont, this.SelectionFont.Style | style); else this.SelectionFont = new Font(this.SelectionFont, this.SelectionFont.Style & ~style); return; } using (EnhancedRichTextBox rtbTemp = new EnhancedRichTextBox()) { // Step through the selected text one char at a time rtbTemp.Rtf = this.SelectedRtf; for (int i = 0; i < len; ++i) { rtbTemp.Select(rtbTempStart + i, 1); //add or remove style if (add) rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style | style); else rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style & ~style); } // Replace & reselect rtbTemp.Select(rtbTempStart, len); this.SelectedRtf = rtbTemp.SelectedRtf; this.Select(rtb1start, len); } return; } ``` I then changed the click methods to use the following pattern: ``` private void tsBold_Click(object sender, EventArgs e) { enhancedRichTextBox1.ChangeFontStyle(FontStyle.Bold, tsBold.Checked); enhancedRichTextBox1.Focus(); } ```