Как сохранить форматирование RichText (жирным/курсивом/etc) при смене какого-либо одного элемента?

У меня есть богатое текстовое поле, которое может содержать строку, содержащую элементы полужирного, курсива или даже разных шрифтов и размеров. Если я выберу всю строку, включая все различия, как я могу выделить "Жирным шрифтом" эту строку без преобразования всей строки в общий шрифт с помощью только "жирного" атрибута?

Например: я хочу повернуть "Это немного text" в " Это несколько text"

Обратите внимание, что "некоторые" остались курсивом, а "текст" остался другим шрифтом.

То, что у меня сейчас, довольно упрощено:

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

Конечно, это применит тот же самый шрифт ко всему выбору. Есть ли способ просто добавить "жирный шрифт" к существующим шрифтам?

ANSWER Хотя "официальный" ответ ниже - только верхушка айсберга, это был толчок, который мне нужен в правильном направлении. Спасибо за подсказку.

Здесь мое официальное исправление:

Я добавил это к моему объекту RichTextBox:

    /// <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;
    }

Затем я изменил методы кликов, чтобы использовать следующий шаблон:

    private void tsBold_Click(object sender, EventArgs e)
    {
        enhancedRichTextBox1.ChangeFontStyle(FontStyle.Bold, tsBold.Checked);

        enhancedRichTextBox1.Focus();
    }

Ответ 1

RTB не поддерживает это. Вы даже не можете обнаружить диапазон символов в пределах выбора, который имеет тот же стиль шрифта. Сначала, сначала проверив свойство SelectionFont, он будет пустым, если выбор содержит сочетание стилей. Если это произойдет, вам придется повторять выбор одного символа за раз, задав свойства SelectionStart и SelectionLength, прочитайте SelectionFont, пока он не изменится. Примените измененный шрифт к найденному вами диапазону.

Отметьте этот ответ, чтобы сохранить это достаточно быстро и без мерцания.

Обратите внимание, что реализация редактора с RTB является любимым темой на codeproject.com. Заимствование кода, если не весь проект, является хорошим способом уменьшить боль.

Ответ 2

Чтобы сделать выделение текста полужирным, сохраняя его форматирование неповрежденным, используйте это:

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

Чтобы отменить выбор текста без сохранения его форматирования, используйте это:

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

Обратите внимание, что приведенный выше код будет работать, только если весь выделенный текст имеет одинаковое форматирование (размер шрифта, стиль и т.д.). Это обнаружено, сначала проверяя свойство SelectionFont, оно будет равно null, если выбор содержит сочетание стилей.

Теперь, чтобы сделать это со всем текстом в richtextbox,

Теперь, чтобы выделить Bold/unBold весь текст richtextbox, сохранив при этом другое форматирование, вам нужно пропустить все символы richtextbox и применить Bold/UnBold один за другим. Вот полный код:

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

Ответ 3

Если вы хотите изменить семейство шрифтов и размер шрифта, вы можете использовать этот метод: Ганс прав, вы должны повторять каждый символ.

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

Для получения дополнительных пояснений вы можете перейти к: http://how-to-code-net.blogspot.ro/2014/01/how-to-make-custom-richtextbox-control.html

Ответ 4

Мне еще предстоит проверить его в терминах ссылок на объекты шрифтов, потребляющих больше памяти, однако

Это должно работать

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

Ответ 5

если вы хотите применить больше FontStyle в том же тексте, вы можете использовать побитовые операторы | и ~ | добавляет новый стиль и ~ удаляет существующий стиль например

Font aFont=new Font(aPrototypeFont, anotherFont.Style | FontStyle.Bold);