突出显示 FlowDocument 中的部分文本

Posted

技术标签:

【中文标题】突出显示 FlowDocument 中的部分文本【英文标题】:Highlight parts of text in FlowDocument 【发布时间】:2013-09-16 15:06:28 【问题描述】:

我想根据搜索结果突出显示FlowDocument 中的某些文本部分。我正在做的是获取在FlowDocument的文本中出现搜索词的索引,然后在从找到的索引开始的文本范围上应用背景色,以找到的索引+搜索词长度结束。

TextRange content = new TextRange(myFlowDocument.ContentStart, 
                                  myFlowDocument.ContentEnd);
List<int> highlights = GetHighlights(content.Text, search);

foreach (int index in highlights)

    var start = myFlowDocument.ContentStart;
    var startPos = start.GetPositionAtOffset(index);
    var endPos = start.GetPositionAtOffset(index + search.Length);
    var textRange = new TextRange(startPos, endPos);
    textRange.ApplyPropertyValue(TextElement.BackgroundProperty, 
               new SolidColorBrush(Colors.Yellow));


TextRange newRange = new TextRange(myFlowDocument.ContentStart, 
                                   newDocument.ContentEnd);
FlowDocument fd = (FlowDocument)XamlReader.Parse(newRange.Text);

问题是,我正在搜索文档文本中的索引,但是当我返回 FlowDocument 时,添加了 xaml 标记并且我看到突出显示移动了。 我该如何解决?

【问题讨论】:

【参考方案1】:

最后,受到 user007 回答的启发,在进行了一些修改后,我设法突出显示了 FlowDocument 中字符串的所有出现。这是我的代码:

for (TextPointer position = newDocument.ContentStart;
        position != null && position.CompareTo(newDocument.ContentEnd) <= 0;
        position = position.GetNextContextPosition(LogicalDirection.Forward))

    if (position.CompareTo(newDocument.ContentEnd) == 0)
    
        return newDocument;
    

    String textRun = position.GetTextInRun(LogicalDirection.Forward);
    StringComparison stringComparison = StringComparison.CurrentCulture;
    Int32 indexInRun = textRun.IndexOf(search, stringComparison);
    if (indexInRun >= 0)
    
        position = position.GetPositionAtOffset(indexInRun);
        if (position != null)
        
            TextPointer nextPointer = position.GetPositionAtOffset(search.Length);
            TextRange textRange = new TextRange(position, nextPointer);
            textRange.ApplyPropertyValue(TextElement.BackgroundProperty, 
                          new SolidColorBrush(Colors.Yellow));
        
    

【讨论】:

【参考方案2】:

您需要使用GetNextContextPosition(LogicalDirection.Forward) 进行迭代并获取TextPointer,将此与先前的TextPointer 一起使用以构造TextRange。在这个TextRange 上,你可以应用你的逻辑。

你不能做的是使用来自FlowDocument 的单个 TextRange 来搜索文本。 FlowDocument 不仅仅是文字:

    private void Button_Click(object sender, RoutedEventArgs e)
    
        String search = this.content.Text;

        TextPointer text = doc.ContentStart;
        while (true)
        
            TextPointer next = text.GetNextContextPosition(LogicalDirection.Forward);
            if (next == null)
            
                break;
            
            TextRange txt = new TextRange(text, next);

            int indx = txt.Text.IndexOf(search);
            if (indx > 0)
            
                TextPointer sta = text.GetPositionAtOffset(indx);
                TextPointer end = text.GetPositionAtOffset(indx + search.Length);
                TextRange textR = new TextRange(sta, end);
                textR.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
            
            text = next;
        
    

更新: 它并非始终有效,例如,如果您有列表,则特殊字符 (\t) 会被 IndexOf 计算在内,但 GetPositionAtOffset 不会将它们计算在内:

•   ListItem 1
•   ListItem 2
•   ListItem 3

这一行:

int indx = txt.Text.IndexOf(search);

可以替换为:

int indx = Regex.Replace(txt.Text, 
     "[^a-zA-Z0-9_.]+", "", RegexOptions.Compiled).IndexOf(search);

【讨论】:

非常感谢您的帮助。我正在尝试您的代码,但它仅突出显示搜索文本的第一次出现。我现在正在尝试对其进行修改以显示所有出现的情况。【参考方案3】:

kzub 的答案似乎对我不起作用,因此我还创建了一个扩展 user007 的解决方案,以突出显示 TextPointer 文本中子字符串的所有实例。它还会忽略大小写并突出显示所有匹配项:

    public static void HighlightWords(TextPointer text, string searchWord, string stringText)
    
        int instancesOfSearchKey = Regex.Matches(stringText.ToLower(), searchWord.ToLower()).Count;

        for (int i = 0; i < instancesOfSearchKey; i++)
        
            int lastInstanceIndex = HighlightNextInstance(text, searchWord);
            if (lastInstanceIndex == -1)
            
                break;
            
            text = text.GetPositionAtOffset(lastInstanceIndex);
        
    

    private static int HighlightNextInstance(TextPointer text, string searchWord)
    
        int indexOfLastInstance = -1;

        while (true)
        
            TextPointer next = text.GetNextContextPosition(LogicalDirection.Forward);
            if (next == null)
            
                break;
            
            TextRange newText = new TextRange(text, next);

            int index = newText.Text.ToLower().IndexOf(searchWord.ToLower());
            if (index != -1)
            
                indexOfLastInstance = index;
            

            if (index > 0)
            
                TextPointer start = text.GetPositionAtOffset(index);
                TextPointer end = text.GetPositionAtOffset(index + searchWord.Length);
                TextRange textRange = new TextRange(start, end);
                textRange.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
            
            text = next;
        

        return indexOfLastInstance;
    

【讨论】:

以上是关于突出显示 FlowDocument 中的部分文本的主要内容,如果未能解决你的问题,请参考以下文章

Python - pyqt5 - 清除 QTextBrowser 的选择

突出显示链接

突出显示时,表格单元格中的 iOS 自定义按钮变暗

突出显示和编辑长字符串中的文本

在 QPlainTextEdit 中突出显示部分文本

如何在textarea中突出显示部分文本