我对FlowDocument有误解,请帮助我看清楚。 我正在使用源代码编辑器,用户可以在其中添加一些特殊变量,然后在程序中查找该变量。对于此编辑器,我使用的是RichTextBox(RTB)。我想为这些变量使用颜色。当用户向文本中添加新变量时,添加颜色不是问题。但是,当用户打开源代码时,首先已经有一些变量的地方,我必须仔细阅读整个文本并为变量着色。
以下代码: 首先,我用正则表达式搜索所有变量及其位置。(变量看起来像:<* variable *>)然后循环通过槽并逐一更改颜色,但是当我制作TextRange时,GetPositionAtOffset会返回错误的值。我知道这是因为特殊格式的字符也被GetPositionAtOffset计数。 问题是,我该如何解决?
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:
在article解决方案之后,我更改了代码。
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 *>的单词。它可以找到所有单词,但是格式字符仍然有问题。
This is the result. The second word in the line has wrong coloring position
This is how the line looks like, when it search for the word
我看到了问题,当我添加color属性时,它会移动数据,但是我的匹配项包含了着色之前的位置。
这看起来很简单,如果我在一行中有多个匹配项,我总是将位置偏移恒定值。但是格式字符看起来并不总是相同的长度。正如您在第二次尝试中看到的那样,第一个可变颜色是正确的。比第二个具有5个字符移位,第三个变量也具有5个字符移位,第四个变量具有9个字符移位,第五个变量具有13个字符移位,第六个...(我不知道这是怎么回事) ,最后一个第七变量也具有良好的颜色位置。
答案 0 :(得分:0)
我并不是说这是最迷人的方式,但是RichTextBox
控件在标准WPF
工具包中并不是很容易使用。因此,这是我已经完成您尝试完成的工作的方式。
本质上,此拆分将获取原始内容,将其拆分为流文档元素,然后遍历文档中的每个单词作为文本范围。然后,如果格式符合Foreach
中所述的条件,则它将格式应用于每个单词。希望这会有所帮助。
P.S在考虑了这一点之后可能并不需要所有代码,因为我的实现也具有跳转到行的功能,因此为什么我将文档分成几行。祝你好运!
//new doc.
var doc = new FlowDocument();
//loop all lines from text.(split on \r\n)
string[] lines = RichTextBoxExtraControl.Text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
for (int i = 0; i < lines.Length; i++)
{
//make new paragraph
var run = new Run(lines[i]);
var par = new Paragraph(run);
par.LineHeight = 1;
doc.Blocks.Add(par);
}
//Searches a list of all words to highlight in place the words below
IEnumerable<TextRange> wordRanges = GetAllWordRanges(doc);
foreach (TextRange wordRange in wordRanges)
{
if (wordRange.Text == ">WORD YOU WANT TO HIGHLIGHT<")
{
wordRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Red); //Effect to apply.
}
}
//Set document.
RichTextBox1.Document = doc;
}
使用此方法Highlighting keywords in a richtextbox in WPF
public static IEnumerable<TextRange> GetAllWordRanges(FlowDocument document)
{
string pattern = @"[^\W\d](\w|[-']{1,2}(?=\w))*";
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);
}
}
答案 1 :(得分:0)
我找到了问题和解决方案。
问题: 当正则表达式在一行中找到所有匹配项时,就没有颜色格式。但是,当我将颜色格式添加到第一个匹配项时,它会移动文本,但是regex匹配结果仍然有旧位置。
解决方案: 始终只更改第一场比赛。完成后,获取新的文本指针,这将使您在带颜色的单词之前返回文本。然后再次给您上色的单词(由于两次上色,它必须跳过)。然后,在您的彩色单词之后返回文本,该单词包含该行中的其他特殊单词。
示例: 我想给单词加上颜色:<* word *>。
要着色的文本:“这是<* test *> <*句子*>。”
第一步:退回整行。正则表达式给出了2个匹配项 (<*测试*>,<*句子*>)。为第一个着色。
第二步:回馈:“这是一个”。不做任何事
结束
{
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);
}
}