如果您可以以.NET Framework 3.5及更高版本为目标,需要在每次更改时扫描文档:只需订阅TextChanged事件并使用TextChangedEventArgs.Changes属性获取更改列表。
每当您收到一个TextChanged事件时,迭代Changes集合并从Offset,AddedLength和RemovedLength构造一个TextRange。然后展开适当的TextRange以重新计算格式,然后执行格式化计算并将其更新为独立步骤(在Dispatcher.BeginInvoke回调中),以便最终不会产生递归TextChanged事件。
richTextBox.TextChanged += (obj, e)
{
var document = richTextBox.Document;
var length = document.ContentStart.GetOffsetToPosition(document.ContentEnd);
int totalAdd = 0;
int totalRemove = 0;
foreach(var change in e.Changes)
{
var expandBy = Math.Max(totalAdd,totalRemove);
var startIndex = change.Offset - expandBy;
var endIndex = changed.Offset + expandBy + Math.Max(totalAdd, totalRemove);
startIndex = Math.Max(startIndex, 0);
endIndex = Math.Min(endIndex, length);
var startPointer = document.ContentStart.GetPositionAtOffset(startIndex);
var endPointer = startPointer.GetPositionAtOffset(endIndex - startIndex);
var range = new TextRange(startPointer, endPointer);
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
DoParsingAndFormatting(ExpandRangeToUnitOfParsing(range));
});
totalAdd += change.AddedLength;
totalRemove += change.RemovedLength;
}
};
如果你想找到的段落,其中一个变化的开始或结束,您可以使用range.Start.Paragraph
和range.End.Paragraph
。
此外,对于许多情况,将独立于FlowDocument本身的所有文本的副本存储在文档中将会有所帮助。然后,当您对该文档应用更改时,您可以随时更新格式,而无需重新阅读文档。请注意,文本不应该存储在一个大型数组中,而应剪成小块(可能大约1000个字符),并通过按索引组织这些块的树来访问。原因是在巨大数组的开头插入一个字符非常昂贵。
上面的代码仍然适用于最新的WPF RichTextBox?我在问,因为我看到一些必要的变化,使代码正常工作,如startindex,endindex没有正确读取文本更改值,需要重新计算..? – 2013-07-29 22:52:29
JP我想你会发现它只是一个错误的情况。原则是合理的,但找出合适的指标值的实际逻辑并不完全正确。 – donovan 2013-12-16 03:34:04