I am trying to get a TextRange from a WPF FlowDocument ListItem:
var doc = new FlowDocument();
doc.Blocks.Add(new List(new ListItem(new Paragraph(new Run("first bullet")))));
If I now try to get a TextRange with
var range1 = new TextRange(doc.ContentStart, doc.ContentEnd);
or
var range2 = new TextRange(doc.ContentStart.GetNextInsertionPosition(LogicalDirection.Forward), doc.ContentEnd);
I get a range where the Text property returns
• first bullet
And if I try
var range3 = new TextRange(doc.ContentStart.GetNextInsertionPosition(LogicalDirection.Forward).GetNextInsertionPosition(LogicalDirection.Forward), doc.ContentEnd);
the Text property returns
irst bullet
The debugger shows:
range1.Start.Offset == 4
range2.Start.Offset == 4
range3.Start.Offset == 5
How could I create a TextRange which points to "first bullet" only (without the bullet and the separating tab)?
The problem here is not in TextRange itself (range1 points exactly to the text you need), but rather in its Text property. Let's refer to the implementation of ITextRange.Text.
It calls GetText(ITextRange thisRange) from TextRangeBase internal class, that intentionally moves starting TextPoiner backwards to include initial list marker (if any) and after that calls GetTextInternal(ITextPointer startPosition, ITextPointer endPosition) with updated starting TextPointer.
This behavior can be reproduced with reflection:
var textRangeBase = typeof(TextRange).Assembly.GetType("System.Windows.Documents.TextRangeBase");
var getTextInternal = textRangeBase.GetMethod("GetTextInternal"
, BindingFlags.NonPublic | BindingFlags.Static, null
, new Type[] { typeof (TextPointer), typeof(TextPointer) }, null);
var text1 = getTextInternal.Invoke(null, new[] { range1.Start, range1.End });
var text2 = getTextInternal.Invoke(null, new[] { range1.Start
.GetNextContextPosition(LogicalDirection.Backward)
.GetNextContextPosition(LogicalDirection.Backward)
.GetNextContextPosition(LogicalDirection.Backward)
, range1.End });
//Results:
//text1: "first bullet\r\n"
//text2: "•\tfirst bullet\r\n"