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();
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With