views:

448

answers:

2

I have a WPF RichTextBox that I am typing some text into and then parsing the whole of the text to do processing on. During this parse, I have the absolute character positions of the start and end of each word.

I would like to use these character positions to apply formatting to certain words. However, I have discovered that the FlowDocument uses TextPointer instances to mark positions in the document.

I have found that I can create a TextRange by constructing it with start and end pointers. Once I have the TextRange I can easily apply formatting to the text within it. I have been using GetPositionAtOffset to get a TextPointer for my character offset but suspect that its offset is different from mine because the selected text is in a slightly different position from what I expect.

My question is, how can I accurately convert an absolute character position to a TextPointer?

A: 

I had exact similar problem, I found out that there is a bug in RichTextBox because it does not count "new line characters - \r\n", so as your line numbers increase, you will find that your offset is positioned wrong by line number count, and I had solved my problems by offsetting line number from offset.

Akash Kava
Hi Akash,Thanks for your reply. My experience is that it IS counting my new line characters but have noticed that completely blank lines "<Paragraph><Run xml:lang="en-gb" xml:space="preserve" /></Paragraph>" are causing the FlowDocument to be 2 characters ahead of my offsets (cumulating after each linebreak).Alan
Alan Spark
+1  A: 

I didn't find a reliable way of converting absolute character positions into TextPosition instances.

My alternative solution was to modify the original parse to work on individual runs rather than capturing the whole text of the RichTextBox. Working with character positions that are relative to a specific Run instance has proved reliable for me. I think that moving my mindset more towards the WPF way of thinking has helped.

I took the following approach for navigating runs in the FlowDocument (inspired by http://blogs.msdn.com/prajakta/archive/2006/10/12/customize-richtextbox-to-allow-only-plain-text-input.aspx):

// Get starting pointer
TextPointer navigator = flowDocument.ContentStart;

// While we are not at end of document
while (navigator.CompareTo(flowDocument.ContentEnd) < 0)
{
    // Get text pointer context
    TextPointerContext context = navigator.GetPointerContext(LogicalDirection.Backward);

    // Get parent as run
    Run run = navigator.Parent as Run;

    // If start of text element within run
    if (context == TextPointerContext.ElementStart && run != null)
    {
        // Get text of run
        string runText = run.Text;

        // ToDo: Parse run text
    }

    // Get next text pointer
    navigator = navigator.GetNextContextPosition(LogicalDirection.Forward);
}
Alan Spark