WPF:从ListItem内容中获取TextRange

时间:2018-01-13 12:49:26

标签: wpf flowdocument textrange

我正在尝试从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(没有子弹和分离标签)?

1 个答案:

答案 0 :(得分:2)

这里的问题不在TextRange本身( range1 完全指向您需要的文本),而是在Text属性中。我们来参考ITextRange.Text的实现。

它从TextRangeBase内部类调用GetText(ITextRange thisRange)故意将TextPoiner向后移动到包含初始列表标记(如果有),之后调用{{ 3}}更新了启动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"