If you can configure NET Framework 3.5 and higher, you donโt need to scan the document every time you change: just subscribe to the TextChanged event and use the TextChangedEventArgs.Changes property to get a list of changes.
Whenever you get a TextChanged event, iterate through a collection of changes and build a TextRange from Offset, AddLength and RemovedLength. Then expand this TextRange if necessary to recalculate the formatting, then do the calculation and update the formatting as a separate step (in the Dispatcher.BeginInvoke callback) so that you don't get recursive TextChanged events.
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; } };
If you want to find the paragraph where the change begins or ends, you can use range.Start.Paragraph and range.End.Paragraph .
In addition, for many situations it will be useful to keep a copy of all the text in the document separately from the FlowDocument itself. Then, when you apply the changes to this document, you can update the formatting as you go without rereading the document. Please note that the text should not be stored in one large array, but fragmented into small parts (maybe about 1000 characters) and accessed through a tree that organizes fragments by index. The reason is that inserting a character at the beginning of a huge array is very expensive.
source share