WPF:从 ListItem 内容获取 TextRange

WPF: get TextRange from ListItem content

我正在尝试从 WPF FlowDocument ListItem 获取 TextRange:

var doc = new FlowDocument();
doc.Blocks.Add(new List(new ListItem(new Paragraph(new Run("first bullet")))));

如果我现在尝试使用

获取 TextRange
var range1 = new TextRange(doc.ContentStart, doc.ContentEnd);

var range2 = new TextRange(doc.ContentStart.GetNextInsertionPosition(LogicalDirection.Forward), doc.ContentEnd);

我得到一个范围,其中文本 属性 returns

•   first bullet

如果我尝试

var range3 = new TextRange(doc.ContentStart.GetNextInsertionPosition(LogicalDirection.Forward).GetNextInsertionPosition(LogicalDirection.Forward), doc.ContentEnd);

正文属性returns

irst bullet

调试器显示:

range1.Start.Offset == 4
range2.Start.Offset == 4
range3.Start.Offset == 5

如何创建一个仅指向 "first bullet" 的 TextRange(没有项目符号和分隔符)?

这里的问题不在于 TextRange 本身(range1 恰好指向您需要的文本),而在于它的文本 属性。参考ITextRange.Text.

的实现

它使用更新的起始 TextPointer 调用 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)

可以通过反射重现此行为:

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"