7

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 标记并且我看到突出显示移动了。我该如何解决?

4

3 回答 3

4

最后,受到 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));
        }
    }
}
于 2013-09-17T12:14:46.603 回答
3

您需要迭代 usingGetNextContextPosition(LogicalDirection.Forward)和 get TextPointer,将这个与之前的一起使用TextPointer来构造TextRange。在此TextRange您可以应用您的逻辑。

你不能做的是使用单个 TextRange fromFlowDocument来搜索文本。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);
于 2013-09-12T11:02:11.460 回答
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;
    }
于 2018-07-18T21:54:03.513 回答