如何突出显示 RichTextBox 中的特定文本?

How to highlight specific text in a RichTextBox?

RichTextBox 控件中,我试图以红色突出显示特定文本作为正则表达式匹配的结果。

样本:

此文本语句工作正常并以红色阴影突出显示 'Deans':

select top 10 * from client where MailName='Deans'

此文本语句也可以正常工作并以红色阴影突出显示代码:

select top 10 * from client where MailName='De a ns'

但是这条语句失败了:

select top 10 * from client where MailName='Deans '

它失败了,因为单引号之间有 space,它在开始 TextRange at

的行上抛出异常
TextRange result = new TextRange(start, start.GetPositionAtOffset(word.Length)); 

例外说:

invalid parameter position 2.

请给我一个解决方案。我哪里出错了?

这是代码片段:

string StringFromRichTextBox(RichTextBox rtb)
{
    TextRange textRange = new TextRange(rtb.Document.ContentStart,      
                rtb.Document.ContentEnd);

    return textRange.Text;
}

private void TextChangedEventHandler(object sender, TextChangedEventArgs e)
{
    TextRange documentRange = new TextRange(txtQueries.Document.ContentStart, txtQueries.Document.ContentEnd);
        documentRange.ClearAllProperties();

    MatchCollection match = Regex.Matches(StringFromRichTextBox(txtQueries), @"'([^']*)'");
    for (int z = 0; z < match.Count; z++)
    {
        CheckKeyword(documentRange, match[z].ToString().Trim());
    }
}

private void CheckKeyword(TextRange textRange, string word)
{
    //txtQueries.TextChanged -= this.TextChangedEventHandler;
    if (textRange.Text.Contains(word))
    {
        int offset = textRange.Text.IndexOf(word);
        if (offset < 0)
        {
            return;
        }// Not found
        else
        {
            // Try to select the text as a contiguous range
            for (TextPointer start = textRange.Start.GetPositionAtOffset(offset); start != textRange.End; start = start.GetPositionAtOffset(1))
            {
                try
                {
                    TextRange result = new TextRange(start, start.GetPositionAtOffset(word.Length));
                    if (result != null && result.Text == word)  
                    {
                        result.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
                        break;
                    }
                }
                catch(Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }
    }
    //txtQueries.TextChanged += this.TextChangedEventHandler;
}

错误信息:

Value cannot be null. Parameter name: position2 at System.Windows.Documents.TextRange..ctor(TextPointer position1, TextPointer position2)

解决方案 :: 向偏移长度添加 4 以说明 richtextbox 中 space 出现的特殊不可见字符。

    var length = word.Length;
                // Try to select the text as a contiguous range
                for (TextPointer start = textRange.Start.GetPositionAtOffset(offset); start != textRange.End; start = start.GetPositionAtOffset(1))
                {
                    try
                    {

                        TextRange result = new TextRange(start, start.GetPositionAtOffset(word.Contains(" ") ? word.Length + 4: word.Length)); //Added 4 to the offset length to account for special invisible characters coming up with space in richtext box
                        if (result.Text.Trim() == word.Trim())  
                        {
                            result.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.Red));
                            break;
                        }

                    }
                    catch (Exception ex)
                    {
                        throw new Exception(ex.Message);
                    }

我在解决这个问题时也遇到了很多麻烦!在使用 GetPositionAtOffset 进行了大量 wtf 之后,我想出了这种方法来在 RichTextBox:

中搜索时获得准确的 TextPointers
public static TextRange FindStringRangeFromPosition(TextPointer position, string str) {
     //what makes this work is checking the PointerContext so you avoid the markup characters   
     while (position != null) {
            if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text) {
                string textRun = position.GetTextInRun(LogicalDirection.Forward);

                // Find the starting index of any substring that matches "str".
                int indexInRun = textRun.IndexOf(str);
                if (indexInRun >= 0) {
                //since we KNOW we're in a text section we can find the endPointer by the str.Length now
                    return new TextRange(position.GetPositionAtOffset(indexInRun), position.GetPositionAtOffset(indexInRun + str.Length));
                }
            }
            position = position.GetNextContextPosition(LogicalDirection.Forward);
        }

        // position will be null if "str" is not found.
        return null;
    }