在 C# 中突出显示 RichTextBox 的括号部分

Highlight bracketed parts of RichTextBox in C#

我需要一种方法来动态地(在 TextChanged 事件上)突出显示 RichTextBox 中括号内的部分,但我被卡住了。 例如,如果文本是:

"This is a {very nice} and {peaceful} morning"

“{very nice}”和“{peacefull}”部分(包括括号)应该使用不同的文本颜色。

您可能正在寻找具有语法高亮显示的 RichTextBox(您尝试突出显示的内容类似于代码编辑器中的字符串高亮显示)。 Whosebug 上有很多问题已经有了很好的答案,例如 A textbox/richtextbox that has syntax highlighting? [C#]。如果您必须使用 RichTextBox,您可以使用以下代码开始

private void rtb_TextChanged(object sender, EventArgs e) {
        var cursorPosition = rtb.SelectionStart;

        rtb.SelectAll();
        rtb.SelectionColor = Color.Black;

        var partsToHighlight = Regex.Matches(rtb.Text, "{[^}{]*}")
            .Cast<Match>()
            .ToList();

        foreach (var part in partsToHighlight) {
            rtb.Select(part.Index, part.Length);
            rtb.SelectionColor = Color.Red;
        }

        rtb.Select(cursorPosition, 0);
    }

不幸的是,它会导致闪烁、丢失滚动条位置并且在处理大块文本时可能需要一些时间。更好的方法是使用一些自定义控件,例如闪烁体:

public partial class Form1 : Form {
    private readonly CustomLexer _lexer = new CustomLexer();

    public Form1() {
        InitializeComponent();

        var editor = new ScintillaNET.Scintilla {
            Dock = DockStyle.Fill,

        };
        this.Controls.Add(editor);

        editor.StyleResetDefault();
        editor.Styles[Style.Default].Font = "Consolas";
        editor.Styles[Style.Default].Size = 10;
        editor.StyleClearAll();

        editor.Styles[CustomLexer.StyleText].ForeColor = Color.Black;
        editor.Styles[CustomLexer.StyleParens].ForeColor = Color.Red;


        editor.Lexer = Lexer.Container;
        editor.StyleNeeded += scintilla_StyleNeeded;
    }

    private void scintilla_StyleNeeded(object sender, StyleNeededEventArgs e) {
        var scintilla = (ScintillaNET.Scintilla)sender;

        var startPos = scintilla.GetEndStyled();
        var endPos = e.Position;

        _lexer.Style(scintilla, startPos, endPos);
    }
}

public class CustomLexer {
    public const int StyleText = 0;
    public const int StyleParens = 1;

    private const int STATE_TEXT = 0;
    private const int STATE_INSIDE_PARENS = 1;

    public void Style(Scintilla scintilla, int startPosition, int endPosition) {
        // Back up to the line start

        var startLine = scintilla.LineFromPosition(startPosition);
        var endLine = scintilla.LineFromPosition(endPosition);

        var fixedStartPosition = scintilla.Lines[startLine].Position;
        var fixedStopPosition = scintilla.Lines[endLine].Position + scintilla.Lines[endLine].Length;

        scintilla.StartStyling(fixedStartPosition);

        bool insideBrackets = false;
        for (var i = fixedStartPosition; i < fixedStopPosition; i++) {
            var c = (char)scintilla.GetCharAt(i);

            if (c == '{') insideBrackets = true;

            if (insideBrackets) {
                scintilla.SetStyling(1, StyleParens);
            }
            else {
                scintilla.SetStyling(1, StyleText);
            }

            if (c == '}') insideBrackets = false;
        }
    }
}

这是基于很棒的教程 here