What I would like to do is get an integer index of a TextPointer, as if the flowDocument was just a normal string. So basically I want to replicate the indexOf method of String, but for a flowDocument instead.
I currently have this partially working solution:

private int GetIntFromPointer(TextPointer mark, FlowDocument document)
        {
            int count=0;
            TextPointer startPointer = document.ContentStart;
            while(startPointer.CompareTo(mark) < 0)
            {
                if(startPointer.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
                    count++;
                startPointer = startPointer.GetNextInsertionPosition(LogicalDirection.Forward);
                if(startPointer.CompareTo(document.ContentEnd)==0)
                    return count;
            }
            return count;
        }

Unfortunately, the resulting index returned by GetIntFromPointer seems to be inaccurate as it attempts to determine the index of TextPointers which are far in the flowDocument. And I don't know why that is the case. I am checking the pointerContext to be sure I am only incrementing when I am looking at text, but I guess there is something I don't understand. Are escape character's being counted?
Otherwise, this method is used in conjunction with a method which accepts an integer index and returns a TextPointer and I am quite confident that method is reliable.

Any ideas as to what I am doing wrong in this method?

Dani AI

Generated

The loop in 's first post undercounts because it increments once per insertion position / text run, not per character. GetNextInsertionPosition advances to the next insertion position (boundaries), and testing for TextPointerContext.Text and doing count++ only counts runs, not the number of characters inside those runs. That explains why the error grows for pointers far into the document.

A simple, accurate fix is to ask WPF for the plain text between ContentStart and the target pointer and use its Length:

int GetIndexFromPointer(TextPointer mark, FlowDocument document)
{
    return new TextRange(document.ContentStart, mark).Text.Length;
}

This mirrors String.IndexOf semantics (counts UTF-16 code units), includes paragraph breaks as newline characters, and represents embedded objects with the object-replacement character. It is the most straightforward way to get a string-style index that matches what String.IndexOf would return on the flattened document text.

Notes and alternatives:

  • TextRange.Text allocates the whole substring; for very large documents or tight loops, iterate runs instead: walk the TextPointer, call GetTextInRun(LogicalDirection.Forward) and add run.Length until the mark is reached; when a mark falls inside a run, use GetOffsetToPosition(mark) to add the partial length and stop. The TextPointer docs (the one pointed to) document GetTextInRun/GetOffsetToPosition and are useful if a low-allocation approach is needed.
  • Be aware of differences between visual glyphs and char counts (surrogate pairs, combining chars) and that embedded elements count as single placeholder characters in the flattened text.
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.