<p>If you need more of AvalonEdit than a simple text box with syntax highlighting, you will first have to learn more about the architecture of AvalonEdit.
<p>If you need more of AvalonEdit than a simple text box with syntax highlighting, you will first have to learn more about the architecture of AvalonEdit.
<p>So, what is the model of a text editor that has support for complex features like syntax highlighting and folding?<br>
<p>So, what is the model of a text editor that has support for complex features like syntax highlighting and folding?<br>
@ -243,7 +245,7 @@ The property <code>TextAnchor.MovementType</code> will be used to determine whic
<h3>TextSegmentCollection</h3>
<h3>TextSegmentCollection</h3>
<p>Sometimes it is useful to store a list of segments and be able to efficiently find all segments overlapping with some other segment.<br>
<p>Sometimes it is useful to store a list of segments and be able to efficiently find all segments overlapping with some other segment.<br>
Example: you might want to store a large number compiler warnings and render squiggly underlines only those that are in the visible region of the document.
Example: you might want to store a large number compiler warnings and render squiggly underlines only for those that are in the visible region of the document.
<p>The <code>TextSegmentCollection</code> serves this purpose. Connected to a document, it will automatically update the offsets of all TextSegment instances inside the collection;
<p>The <code>TextSegmentCollection</code> serves this purpose. Connected to a document, it will automatically update the offsets of all TextSegment instances inside the collection;
but it also has the useful methods <code>FindOverlappingSegments</code> and <code>FindFirstSegmentWithStartAfter</code>.
but it also has the useful methods <code>FindOverlappingSegments</code> and <code>FindFirstSegmentWithStartAfter</code>.
@ -257,6 +259,7 @@ It returns an immutable snapshot of the document. The snapshot is thread-safe, s
The overload <code>CreateSnapshot(out ChangeTrackingCheckpoint)</code> also returns a <code>ChangeTrackingCheckpoint</code> for the document snapshot.
The overload <code>CreateSnapshot(out ChangeTrackingCheckpoint)</code> also returns a <code>ChangeTrackingCheckpoint</code> for the document snapshot.
Once you have two checkpoints, you can call <code>GetChangesTo</code> to retrieve the complete list of document changes that happened between those versions of the document.
Once you have two checkpoints, you can call <code>GetChangesTo</code> to retrieve the complete list of document changes that happened between those versions of the document.
When the <code>TextView</code> needs to construct VisualLines (usually before rendering), it first
determines which <code>DocumentLine</code> is the top-most visible line in the currently viewed region.
From there, it starts to build <code>VisualLine</code>s and also immediately does the conversion to <code>TextLine</code> (word-wrapping).
The process stops once the viewed document region is filled.
<p>
The resulting <code>VisualLine</code>s (and <code>TextLine</code>s) will be cached and reused in future rendering passes.
When the user scrolls down, only the VisualLines coming into view are created, the rest is reused.
<p>
The <code>TextView.Redraw</code> methods are used to remove <code>VisualLine</code>s from the cache.
AvalonEdit calls <code>Redraw</code> automatically on the affected lines when the document is changed; and will invalidate the whole cache
when any editor options are changed. You will only have to call <code>Redraw</code> manually if you write extensions to the VisualLine creation process
that maintain their own data source. For example, the <code>FoldingManager</code> is calling <code>Redraw</code> when text sections are expanded or collapsed.
<p>
Calling <code>Redraw</code> does not cause immediate recreation of the lines.
They are just removed from the cache so that the next rendering step will recreate them.
All <code>Redraw</code> methods will trigger a new rendering step, but they will delay it using the WPF Dispatcher using a low priority.
<h3>Element Generators</h3>
You can extend the text view by registering a custom class deriving from <code>VisualLineElementGenerator</code> in the <code>TextView.ElementGenerators</code> collection.
This allows you to add custom VisualLineElements.
Using the <code>InlineObjectElement</code> class, you can even put interactive WPF controls into the text document.
<p>
For all document text not consumed by element generators, AvalonEdit will create <code>VisualLineText</code> elements.
<p>
Usually, the construction of the <code>VisualLine</code> will stop at the end of the <code>DocumentLine</code>. However, if some <code>VisualLineElementGenerator</code>
creates an element that's longer than the rest of the line, construction of the <code>VisualLine</code> may resume in another <code>DocumentLine</code>.
Currently, only the <code>FoldingElementGenerator</code> can cause one <code>VisualLine</code> to span multiple <code>DocumentLine</code>s.
<p>
<imgsrc="AvalonEdit/folding.png"alt="Screenshot Folding and ImageElementGenerator">
<p>
Here is the full source code for a class that implements embedding images into AvalonEdit:
<prelang="cs">public class ImageElementGenerator : VisualLineElementGenerator
{
readonly static Regex imageRegex = new Regex(@"<img src=""([\.\/\w\d]+)""/?>", RegexOptions.IgnoreCase);
readonly string basePath;
public ImageElementGenerator(string basePath)
{
if (basePath == null)
throw new ArgumentNullException("basePath");
this.basePath = basePath;
}
Match FindMatch(int startOffset)
{
// fetch the end offset of the VisualLine being generated
int endOffset = CurrentContext.VisualLine.LastDocumentLine.EndOffset;
/// Gets the text document that owns this DocumentLine. O(1).
/// Gets the text document that owns this DocumentLine. O(1).
/// </summary>
/// </summary>
/// <remarks>This property is still available even if the line was deleted.</remarks>
/// <remarks>This property is still available even if the line was deleted.</remarks>
[ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. It will be removed in a future AvalonEdit version.")]
[ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. "+
"It will be removed in a future AvalonEdit version.")]
/// <exception cref="InvalidOperationException">The line was deleted.</exception>
/// <exception cref="InvalidOperationException">The line was deleted.</exception>
[ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. It will be removed in a future AvalonEdit version.")]
[ObsoleteAttribute("Supporting this property causes DocumentLine to use more memory than otherwise necessary. "+
"It will be removed in a future AvalonEdit version. "+