C# WPF 为 RichTextBox 文本中的特定单词着色 [英] C# WPF colorize specific words in RichTextBox text

查看:57
本文介绍了C# WPF 为 RichTextBox 文本中的特定单词着色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 FlowDocument 有误解,请帮我看清楚.我正在开发一个源代码编辑器,用户可以在其中添加一些特殊变量,然后程序会查找这些变量.对于这个编辑器,我使用 RichTextBox(RTB).我想为这些变量使用颜色.当用户向文本添加新变量时添加颜色不是问题.但是当用户首先打开已经有一些变量的源代码时,我必须遍历整个文本并为变量着色.

I've a misunderstanding about FlowDocument, please help me to see clear. I'm working on a source code editor, where user can add few special variables, and later the program looking for this variables. For this editor, I'm using RichTextBox(RTB). I'd like to use color for these variables. It was not a problem to add color when the user add new variable to the text. But when the user open a source code what has already some variables first I've to go trough on the whole text and colorize the variables.

代码如下:首先我用正则表达式搜索所有变量及其位置.(变量看起来像:<*variable*>)然后循环低谷并一个一个改变颜色,但是当我制作TextRange时,GetPositionAtOffset返回错误价值.我知道这是因为特殊的格式化字符也被 GetPositionAtOffset 计算在内.问题是,我该如何解决这个问题?

The code below: First I'm search all variables and their position with regex.(Variables looks like: <*variable*>) Then loop trough and change the color one by one, but when I'm making the TextRange, the GetPositionAtOffset gives back wrong value. I know it is because of the special formatting characters also counting by GetPositionAtOffset. The question is, how can I solve this?

private void ColorizeAllVariable(TextRange TR_Input)
    {
        Regex regex = new Regex(@"(<\*.[^<\*>]*\*>)");
        MatchCollection matches = regex.Matches(TR_Input.Text);
        NoRTBChangeEvent = true;
        for (int i = 0; i < matches.Count; i++)
        {
            TextRange TR_Temp = new TextRange(TR_Input.Start.GetPositionAtOffset(matches[i].Index), TR_Input.Start.GetPositionAtOffset(matches[i].Index + matches[i].Length));
            TR_Temp.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.DodgerBlue);
        }
        NoRTBChangeEvent = false;
    }

<小时>

更新 1:

按照 user8478480 解决方案,我更改了代码.

Following user8478480 solution, I changed my code.

private void ColorizeAllVariable(RichTextBox richTextBox)
    {
        IEnumerable<TextRange> WordRanges = GetAllWordRanges(richTextBox.Document, @"(<\*.[^<\*>]*\*>)");

        foreach (TextRange WordRange in WordRanges)
        {
            WordRange.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.DodgerBlue);
        }
    }

private static IEnumerable<TextRange> GetAllWordRanges(FlowDocument document, string pattern)
    {
        TextPointer pointer = document.ContentStart;
        while (pointer != null)
        {
            if (pointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
            {
                string textRun = pointer.GetTextInRun(LogicalDirection.Forward);
                MatchCollection matches = Regex.Matches(textRun, pattern);
                foreach (Match match in matches)
                {
                    int startIndex = match.Index;
                    int length = match.Length;
                    TextPointer start = pointer.GetPositionAtOffset(startIndex);
                    TextPointer end = start.GetPositionAtOffset(length);
                    yield return new TextRange(start, end);
                }
            }
            pointer = pointer.GetNextContextPosition(LogicalDirection.Forward);
        }
    }

它是直接寻找看起来像<*word*>的词.它找到了所有单词,但仍然存在格式字符问题.

It is directly looking for the words what looks like <*word*>. And it finds all the word, but still have problem with the formatting characters.

这就是结果.该行中的第二个单词着色位置错误

这是该行在搜索单词时的样子

这是另一个尝试

我看到了问题,当我添加颜色属性时,它会移动数据,但我的匹配包含着色前的位置.

I see the problem, when I add the color property it shifts the data but my match contains the position before the colorization.

看起来很简单,如果我在一行中有多个匹配项,我总是将位置移动一个常数值.但是格式化字符看起来并不总是相同的长度.正如您在第二次尝试中看到的,第一个可变颜色是正确的.比第二个有 5 个字符移位,第三个变量也有 5 个字符移位,第四个变量有 9 个字符移位,第五个变量有 13 个字符移位,第六个......(我不知道这里发生了什么),最后的第七个变量也有很好的颜色位置.

It looks easy, if I have more than one match in one line I always shifting the position by constant value. But the formatting characters doesn't looks like always the same length. As you can see on the second try, the first variable color is correct. Than the second has 5 character shifting, the third variable also has 5 character shifting, the fourth variable has 9 character shifting,the fifth variable has 13 character shifting, the sixth... (I've no idea what is going on here), and the last the seventh variable has also good color position.

推荐答案

我也找到了问题和解决方案.

I found the problem and the solution also.

问题:当正则表达式在一行中找到所有匹配项时,没有颜色格式.但是当我将颜色格式添加到第一个匹配项时,它会移动文本,但正则表达式匹配结果仍然是旧位置.

Problem: When the regex find all matches in a line, there is no color formatting. But when I add the color format to the first match, it shift the text, but the regex match result has still the old positions.

解决方案:始终只更改第一场比赛.完成后,获取新的文本指针,它将返回彩色单词之前的文本.然后再给你着色的单词(它必须跳过,因为两次着色).然后在您的彩色单词之后返回文本,该行中包含其他特殊单词的内容.

Solution: Always change only the first match. When it is done, get the new text pointer what will give you back the text before your colored word. Then gives back again you colored word (It must skip, because of the two times coloring). And than gives back the text after your colored word, what contains the other special words in the line.

示例:我想给单词上色,看起来像:<*word*>.

Example: I want to colorize the words looks like: <*word*>.

要着色的文本:这是一个 <*test*> <*sentence*>."

Text to colorize: "This is a <*test*> <*sentence*>."

  • 第一步:返还整条线.正则表达式给出 2 个匹配项(<*测试*>,<*句子*>).给第一个上色.

  • First step: Gives back the whole line. Regex gives 2 matches (<*test*>,<*sentence*>). Colorize the first one.

第二步:回馈:这是一个".什么都不做

Second step: Gives back: "This is a ". Do nothing with that

结束

{
    TextPointer pointer = document.ContentStart;
    bool Skip = false;
    string textRun = "";

    while (pointer != null)
    {
        if (pointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
        {
            do
            {
                if (!Skip)
                {
                    textRun = pointer.GetTextInRun(LogicalDirection.Forward);
                    MatchCollection Matches = Regex.Matches(textRun, pattern);
                    if (Matches.Count > 0)
                    {
                        Skip = true;
                        int startIndex = Matches[0].Index;
                        int length = Matches[0].Length;
                        TextPointer start = pointer.GetPositionAtOffset(startIndex);
                        TextPointer end = start.GetPositionAtOffset(length);
                        yield return new TextRange(start, end);
                    }
                }
                else
                {
                    pointer = pointer.GetNextContextPosition(LogicalDirection.Forward);
                    if (pointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
                    {
                        textRun = pointer.GetTextInRun(LogicalDirection.Forward);
                        if(Regex.IsMatch(textRun,pattern))
                        {
                            Skip = false;
                        }
                    }
                }
            } while (Skip);
        }
        pointer = pointer.GetNextContextPosition(LogicalDirection.Forward);
    }
}

这篇关于C# WPF 为 RichTextBox 文本中的特定单词着色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆