突出显示FlowDocument中的部分文本

时间:2013-09-12 09:40:29

标签: c# wpf highlight flowdocument

我想根据搜索结果突出显示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标签被添加,我看到了高亮显示。 我该如何解决?

3 个答案:

答案 0 :(得分:3)

您需要使用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);

答案 1 :(得分:2)

最终,受到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 :(得分:0)

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;
    }