我正在尝试从 WPF FlowDocument ListItem 获取文本范围:
var doc = new FlowDocument();
doc.Blocks.Add(new List(new ListItem(new Paragraph(new Run("first bullet")))));
如果我现在尝试使用
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 本身(range1 完全指向您需要的文本(,而在于其 Text 属性。让我们参考ITextRange.Text的实现。
它从 TextRangeBase 内部类调用 GetText(ITextRange thisRange(,它有意将起始 TextPoiner 向后移动以包含初始列表标记(如果有的话(,然后使用更新的起始 TextPointer 调用 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 bulletrn"
//text2: "•tfirst bulletrn"