我正在尝试在WPF RichTextBox中查找字符串的实例。我现在所拥有的几乎可以用,但是它突出显示了文档的错误部分。

private int curSearchLocation;

private void FindNext_Click(object sender, RoutedEventArgs e)
{
    TextRange text = new TextRange(RichEditor.Document.ContentStart, RichEditor.Document.ContentEnd);
    var location = text.Text.IndexOf(SearchBox.Text, curSearchLocation, StringComparison.CurrentCultureIgnoreCase);
    if (location < 0)
    {
        location = text.Text.IndexOf(SearchBox.Text, StringComparison.CurrentCultureIgnoreCase);
    }
    if (location >= 0)
    {
        curSearchLocation = location + 1;
        RichEditor.Selection.Select(text.Start.GetPositionAtOffset(location), text.Start.GetPositionAtOffset(location + SearchBox.Text.Length));
    }
    else
    {
        curSearchLocation = 0;
        MessageBox.Show("Not found");
    }
    RichEditor.Focus();
}


这是我搜索“文档”时发生的情况:



这是因为GetPositionAtOffset在其偏移量中包含非文本元素,例如打开和关闭标签,这不是我想要的。我找不到忽略这些元素的方法,也找不到直接向想要的文本获取TextPointer的方法,这也可以解决问题。

如何获得突出显示正确文本的信息?

最佳答案

不幸的是,TextRange.Text会去除非文本字符,因此在这种情况下,由IndexOf计算出的偏移量会太低。那是主要问题。

我试图解决您的问题,并找到了即使我们在许多段落中设置了文本格式也能正常工作的解决方案。

CodeProject Article可以提供很多帮助。因此,也请阅读该文章。

int curSearchLocation;
private void FindNext_Click(object sender, RoutedEventArgs e)
{
    TextRange text = new TextRange(RichEditor.Document.ContentStart, RichEditor.Document.ContentEnd);
    var location = text.Text.IndexOf(SearchBox.Text, curSearchLocation, StringComparison.CurrentCultureIgnoreCase);
    if (location < 0)
    {
        location = text.Text.IndexOf(SearchBox.Text, StringComparison.CurrentCultureIgnoreCase);
    }
    if (location >= 0)
    {
        curSearchLocation = location + 1;
        Select(location, SearchBox.Text.Length);
    }
    else
    {
        curSearchLocation = 0;
        MessageBox.Show("Not found");
    }
    RichEditor.Focus();
}

public void Select(int start, int length)
{
    TextPointer tp = RichEditor.Document.ContentStart;

    TextPointer tpLeft = GetPositionAtOffset(tp, start, LogicalDirection.Forward);
    TextPointer tpRight = GetPositionAtOffset(tp, start + length, LogicalDirection.Forward);
    RichEditor.Selection.Select(tpLeft, tpRight);
}

private TextPointer GetPositionAtOffset(TextPointer startingPoint, int offset, LogicalDirection direction)
{
    TextPointer binarySearchPoint1 = null;
    TextPointer binarySearchPoint2 = null;

    // setup arguments appropriately
    if (direction == LogicalDirection.Forward)
    {
        binarySearchPoint2 = this.RichEditor.Document.ContentEnd;

        if (offset < 0)
        {
            offset = Math.Abs(offset);
        }
    }

    if (direction == LogicalDirection.Backward)
    {
        binarySearchPoint2 = this.RichEditor.Document.ContentStart;

        if (offset > 0)
        {
            offset = -offset;
        }
    }

    // setup for binary search
    bool isFound = false;
    TextPointer resultTextPointer = null;

    int offset2 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint2));
    int halfOffset = direction == LogicalDirection.Backward ? -(offset2 / 2) : offset2 / 2;

    binarySearchPoint1 = startingPoint.GetPositionAtOffset(halfOffset, direction);
    int offset1 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint1));

    // binary search loop

    while (isFound == false)
    {
        if (Math.Abs(offset1) == Math.Abs(offset))
        {
            isFound = true;
            resultTextPointer = binarySearchPoint1;
        }
        else
            if (Math.Abs(offset2) == Math.Abs(offset))
            {
                isFound = true;
                resultTextPointer = binarySearchPoint2;
            }
            else
            {
                if (Math.Abs(offset) < Math.Abs(offset1))
                {
                    // this is simple case when we search in the 1st half
                    binarySearchPoint2 = binarySearchPoint1;
                    offset2 = offset1;

                    halfOffset = direction == LogicalDirection.Backward ? -(offset2 / 2) : offset2 / 2;

                    binarySearchPoint1 = startingPoint.GetPositionAtOffset(halfOffset, direction);
                    offset1 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint1));
                }
                else
                {
                    // this is more complex case when we search in the 2nd half
                    int rtfOffset1 = startingPoint.GetOffsetToPosition(binarySearchPoint1);
                    int rtfOffset2 = startingPoint.GetOffsetToPosition(binarySearchPoint2);
                    int rtfOffsetMiddle = (Math.Abs(rtfOffset1) + Math.Abs(rtfOffset2)) / 2;
                    if (direction == LogicalDirection.Backward)
                    {
                        rtfOffsetMiddle = -rtfOffsetMiddle;
                    }

                    TextPointer binarySearchPointMiddle = startingPoint.GetPositionAtOffset(rtfOffsetMiddle, direction);
                    int offsetMiddle = GetOffsetInTextLength(startingPoint, binarySearchPointMiddle);

                    // two cases possible
                    if (Math.Abs(offset) < Math.Abs(offsetMiddle))
                    {
                        // 3rd quarter of search domain
                        binarySearchPoint2 = binarySearchPointMiddle;
                        offset2 = offsetMiddle;
                    }
                    else
                    {
                        // 4th quarter of the search domain
                        binarySearchPoint1 = binarySearchPointMiddle;
                        offset1 = offsetMiddle;
                    }
                }
            }
    }

    return resultTextPointer;
}

int GetOffsetInTextLength(TextPointer pointer1, TextPointer pointer2)
{
    if (pointer1 == null || pointer2 == null)
        return 0;

    TextRange tr = new TextRange(pointer1, pointer2);

    return tr.Text.Length;
}


希望这段代码适合您的情况。

关于c# - RichTextBox在有趣的地方找到我的搜索字词,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21334281/

10-09 05:49
查看更多