Best way to implement Richtextbox parsing / editing in WPF

I'm trying to implement (as a prototype initially) a richtextbox control that can be analyzed in real time to apply certain formatting options to it. This is done in WPF, so I thought the best way to do this is to extend an existing text box control.

I ran into a problem when it is not well documented, and the examples are rather slow (the ones I found parsed the entire document with every keystroke).

The way I decided to do this right now is to create a custom Inline element that can contain formatting tags and content. Therefore, I only need to analyze the current paragraph and the runs in this paragraph to format the tags.

Is there a better way to achieve this? Please note that this is not for code / syntax based documents (therefore AvalonEdit is not suitable).

Greetings

+4
source share
2 answers

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.

+4
source

Take a look here at CodeProject . Here is an article that might interest you regarding a RichTextBox that extends a subclass ... Look at this: a Extended RichTextBox that has more features

-3
source

Source: https://habr.com/ru/post/1303992/


All Articles