How do I maintain RichText formatting (bold/italic/etc) when changing any one element?

后端 未结 5 751
醉酒成梦
醉酒成梦 2020-12-05 15:52

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 d

相关标签:
5条回答
  • 2020-12-05 16:12

    In case you want also to change its font family and font size you could use this method: Hans is right, you have to iterate each character.

      private void ChangeFontStyleForSelectedText(string familyName, float? emSize, FontStyle? fontStyle, bool? enableFontStyle)
        {
            _maskChanges = true;
            try
            {
                int txtStartPosition = txtFunctionality.SelectionStart;
                int selectionLength = txtFunctionality.SelectionLength;
                if (selectionLength > 0)
                    using (RichTextBox txtTemp = new RichTextBox())
                    {
                        txtTemp.Rtf = txtFunctionality.SelectedRtf;
                        for (int i = 0; i < selectionLength; ++i)
                        {
                            txtTemp.Select(i, 1);
                            txtTemp.SelectionFont = RenderFont(txtTemp.SelectionFont, familyName, emSize, fontStyle, enableFontStyle);
                        }
    
                        txtTemp.Select(0, selectionLength);
                        txtFunctionality.SelectedRtf = txtTemp.SelectedRtf;
                        txtFunctionality.Select(txtStartPosition, selectionLength);
                    }
            }
            finally
            {
                _maskChanges = false;
            }
        }
    
          /// <summary>
        /// Changes a font from originalFont appending other properties
        /// </summary>
        /// <param name="originalFont">Original font of text</param>
        /// <param name="familyName">Target family name</param>
        /// <param name="emSize">Target text Size</param>
        /// <param name="fontStyle">Target font style</param>
        /// <param name="enableFontStyle">true when enable false when disable</param>
        /// <returns>A new font with all provided properties added/removed to original font</returns>
        private Font RenderFont(Font originalFont, string familyName, float? emSize, FontStyle? fontStyle, bool? enableFontStyle)
        {
            if (fontStyle.HasValue && fontStyle != FontStyle.Regular && fontStyle != FontStyle.Bold && fontStyle != FontStyle.Italic && fontStyle != FontStyle.Underline)
                throw new System.InvalidProgramException("Invalid style parameter to ChangeFontStyleForSelectedText");
    
            Font newFont;
            FontStyle? newStyle = null;
            if (fontStyle.HasValue)
            {
                if (fontStyle.HasValue && fontStyle == FontStyle.Regular)
                    newStyle = fontStyle.Value;
                else if (originalFont != null && enableFontStyle.HasValue && enableFontStyle.Value)
                    newStyle = originalFont.Style | fontStyle.Value;
                else
                    newStyle = originalFont.Style & ~fontStyle.Value;
            }
    
            newFont = new Font(!string.IsNullOrEmpty(familyName) ? familyName : originalFont.FontFamily.Name,
                                emSize.HasValue ? emSize.Value : originalFont.Size,
                                newStyle.HasValue ? newStyle.Value : originalFont.Style);
            return newFont;
        }
    

    For more explanations you could go to: http://how-to-code-net.blogspot.ro/2014/01/how-to-make-custom-richtextbox-control.html

    0 讨论(0)
  • 2020-12-05 16:12

    I am yet to test it in terms of Font object references consuming more memory however

    This should work

            if(rtbCaseContent.SelectedText.Length > 0 ) 
            {
                // calculate font style 
                FontStyle style = FontStyle.Underline;
                Font selectedFont = rtbCaseContent.SelectionFont;
    
                if (rtbCaseContent.SelectionFont.Bold == true)
                {
                    style |= FontStyle.Bold;
                }
                if (rtbCaseContent.SelectionFont.Italic == true)
                {
                    style |= FontStyle.Italic;
                }
    
                rtbCaseContent.SelectionFont = new Font(selectedFont,style);
            }           
    
    0 讨论(0)
  • 2020-12-05 16:21

    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.

    0 讨论(0)
  • 2020-12-05 16:27

    if you want to apply more FontStyle's on the same text you can use bitwise operators | and ~ | adds a new style and ~ removes an existing style for example

    Font aFont=new Font(aPrototypeFont, anotherFont.Style | FontStyle.Bold); 
    
    0 讨论(0)
  • 2020-12-05 16:31

    To make a text selection bold while keeping its formatting intact, use this:

    if (rtb.SelectionFont !=null)
        rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);
    

    To unBold text selection while keeping its formatting intact, use this:

    if (rtb.SelectionFont !=null)
        rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);
    

    Note that above code will only work, if all the selected text has same formatting (font size, style etc). This is detected by checking the SelectionFont property first, it will be null if the selection contains a mix of styles.

    Now to do this with all text in richtextbox,

    Now to Bold/unBold the entire text of richtextbox while keeping other formatting intact, you need to loop through all the characters of the richtextbox and apply Bold/unBold one by one. Here is the complete code:

    private void tsBold_Click(object sender, EventArgs e)
    {
        //Loop through all the characters of richtextbox
        for (int i = 0; i < rtb.TextLength; i++)
        {
            //Select current character
            rtb.Select(i, 1);
    
            if (tsBold.Checked)
                //Make the selected character Bold
                rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);
            else
                //Make the selected character unBold
                rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);
        }
    }
    

    If you need to toggle the existing state of Bold (i.e. make non-bold text Bold and make bold text unBold), use this instead:

            if (rtb.SelectionFont.Style.ToString().Contains("Bold")) //If the selected character is Bold
                //Make the selected character unBold
                rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);
            else //If the selected character is unBold
                //Make the selected character Bold
                rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);
    
    0 讨论(0)
提交回复
热议问题