1

我正在尝试从 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);

我得到了 Text 属性返回的范围

•   first bullet

如果我尝试

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

Text 属性返回

irst bullet

调试器显示:

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

我如何创建一个仅指向“第一个项目符号”的 TextRange(没有项目符号和分隔选项卡)?

4

1 回答 1

2

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

它从 TextRangeBase 内部类调用GetText(ITextRange thisRange)故意向后移动起始 TextPoiner 以包含初始列表标记(如果有),然后调用GetTextInternal(ITextPointer startPosition, ITextPointer endPosition) 并更新起始 TextPointer。

这种行为可以通过反射重现:

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"
于 2018-01-14T15:35:53.320 回答