~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to samples/AvalonEdit.Sample/article.html

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 
2
<!------------------------------------------------------------>
 
3
<!--                           INTRODUCTION                                
 
4
 
 
5
 The Code Project article submission template (HTML version)
 
6
 
 
7
Using this template will help us post your article sooner. To use, just 
 
8
follow the 3 easy steps below:
 
9
 
 
10
     1. Fill in the article description details
 
11
     2. Add links to your images and downloads
 
12
     3. Include the main article text
 
13
 
 
14
That's all there is to it! All formatting will be done by our submission
 
15
scripts and style sheets. 
 
16
 
 
17
-->  
 
18
<!------------------------------------------------------------>
 
19
<!--                        IGNORE THIS SECTION                            -->
 
20
<html>
 
21
<head>
 
22
<title>AvalonEdit</title>
 
23
<Style>
 
24
BODY, P, TD { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt }
 
25
H2,H3,H4,H5 { color: #ff9900; font-weight: bold; }
 
26
H2 { font-size: 13pt; }
 
27
H3 { font-size: 12pt; }
 
28
H4 { font-size: 10pt; color: black; }
 
29
PRE { BACKGROUND-COLOR: #FBEDBB; FONT-FAMILY: "Courier New", Courier, mono; WHITE-SPACE: pre; }
 
30
CODE { COLOR: #990000; FONT-FAMILY: "Courier New", Courier, mono; }
 
31
</style>
 
32
<link rel="stylesheet" type="text/css" href="http://www.codeproject.com/App_Themes/NetCommunity/CodeProject.css">
 
33
</head>
 
34
<body bgcolor="#FFFFFF" color=#000000>
 
35
<div style="width:600px; margin-left: 24px;">
 
36
<!------------------------------------------------------------>
 
37
 
 
38
 
 
39
<!------------------------------------------------------------>
 
40
<!--  Fill in the details (CodeProject will reformat this section for you) -->
 
41
 
 
42
 
 
43
<!------------------------------------------------------------>
 
44
<!--  Include download and sample image information.                       --> 
 
45
 
 
46
<ul class=download>
 
47
<li><a href="AvalonEdit/AvalonEdit_Binaries.zip">Download binaries - 206.5 KB</a></li>
 
48
<li><a href="AvalonEdit/AvalonEdit_Source.zip">Download source code - 391.3 KB</a></li>
 
49
<li><a href="AvalonEdit/AvalonEdit_CHM_Documentation.zip">Download .chm documentation file - 1.88 MB</a></li>
 
50
</ul>
 
51
<p>The latest version of AvalonEdit can be found as part of the <a href="http://www.icsharpcode.net/OpenSource/SD/">SharpDevelop</a> project.
 
52
For details on AvalonEdit, please see <a href="http://www.avalonedit.net/">www.avalonedit.net</a>.</p>
 
53
 
 
54
<p><img src="AvalonEdit/screenshot.png" width="611" height="441" alt="Sample Image" /></p>
 
55
 
 
56
 
 
57
<!------------------------------------------------------------>
 
58
 
 
59
<!--  Add the article text. Please use simple formatting (<h2>, <p> etc)   --> 
 
60
 
 
61
<h2>Introduction</h2>
 
62
 
 
63
<p>ICSharpCode.AvalonEdit is the WPF-based text editor that I've written for SharpDevelop 4.0. It is meant as a replacement
 
64
for <a href="http://www.codeproject.com/KB/edit/TextEditorControl.aspx">ICSharpCode.TextEditor</a>, but should be:
 
65
<ul>
 
66
<li>Extensible</li>
 
67
<li>Easy to use</li>
 
68
<li>Better at handling large files</li>
 
69
</ul>
 
70
<p>
 
71
<b>Extensible</b> means that I wanted SharpDevelop AddIns to be able to add features to the text editor.
 
72
For example, an AddIn should be able to allow inserting images into comments &ndash; this way you could put
 
73
stuff like class diagrams right into the source code!
 
74
<p>
 
75
With, <b>Easy to use</b>, I'm referring to the programming API. It should just work.
 
76
For example, this means if you change the document text,
 
77
the editor should automatically redraw without having to call <code>Invalidate()</code>.
 
78
 
 
79
And if you do something wrong, you should get a meaningful exception, not corrupted state and crash later at an unrelated location.
 
80
 
 
81
<p>
 
82
<b>Better at handling large files</b> means that the editor should be able to handle large files (e.g.
 
83
the mscorlib XML documentation file, 7 MB, 74100 LOC), even when features like folding (code collapsing) are enabled.
 
84
 
 
85
<h2>Using the Code</h2>
 
86
 
 
87
<p>The main class of the editor is <code>ICSharpCode.AvalonEdit.TextEditor</code>.
 
88
You can use it just similar to a normal WPF <code>TextBox</code>:
 
89
<pre lang="xml">&lt;avalonEdit:TextEditor
 
90
    xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
 
91
    Name="textEditor"
 
92
    FontFamily="Consolas"
 
93
    FontSize="10pt"/&gt;</pre>
 
94
 
 
95
<p>To enable syntax highlighting, use:
 
96
 
 
97
<pre lang="cs">textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");</pre>
 
98
AvalonEdit has syntax highlighting definitions built in for:
 
99
ASP.NET, Boo, Coco/R grammars, C++, C#, HTML, Java, JavaScript, Patch files, PHP, TeX, VB, XML
 
100
 
 
101
<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.
 
102
 
 
103
<!------------------------------------------------------------>
 
104
<h2>Architecture of AvalonEdit</h2>
 
105
<img src="AvalonEdit/dependencies.png" width="583" height="439" alt="Namespace Dependency Graph"/>
 
106
<p>
 
107
As you can see in this dependency graph, AvalonEdit consists of a few sub-namespaces that have cleanly separated jobs.
 
108
Most of the namespaces have a kind of 'main' class.
 
109
<ul>
 
110
<li>ICSharpCode.AvalonEdit.Utils: Various utility classes</li>
 
111
<li>ICSharpCode.AvalonEdit.Document: <code>TextDocument</code> &mdash; text model</li>
 
112
<li>ICSharpCode.AvalonEdit.Rendering: <code>TextView</code> &mdash; extensible view onto the document</li>
 
113
<li>ICSharpCode.AvalonEdit.Editing: <code>TextArea</code> &mdash; controls text editing (e.g. caret, selection, handles user input)</li>
 
114
<li>ICSharpCode.AvalonEdit.Folding: <code>FoldingManager</code> &mdash; enables code collapsing</li>
 
115
<li>ICSharpCode.AvalonEdit.Highlighting: <code>HighlightingManager</code> &mdash; highlighting engine</li>
 
116
<li>ICSharpCode.AvalonEdit.Highlighting.Xshd: <code>HighlightingLoader</code> &mdash; XML syntax highlighting definition support (.xshd files)</li>
 
117
<li>ICSharpCode.AvalonEdit.CodeCompletion: <code>CompletionWindow</code> &mdash; shows a drop-down list for code completion</li>
 
118
<li>ICSharpCode.AvalonEdit: <code>TextEditor</code> &mdash; the main control that brings it all together</li>
 
119
</ul>
 
120
 
 
121
<p>
 
122
Here is the visual tree of the <code>TextEditor</code> control:<br>
 
123
<img src="AvalonEdit/snoop.png" width="272" height="351" alt="Visual Tree"/>
 
124
<p>
 
125
It's important to understand that AvalonEdit is a composite control with the three layers: <code>TextEditor</code> (main control), <code>TextArea</code> (editing), <code>TextView</code> (rendering).
 
126
While the main control provides some convenience methods for common tasks, for most advanced features you have to work directly with the inner controls. You can access them using <code>textEditor.TextArea</code>
 
127
or <code>textEditor.TextArea.TextView</code>.
 
128
 
 
129
<!------------------------------------------------------------>
 
130
<h2>The Text Model: Document</h2>
 
131
 
 
132
<p>The main class of the model is <code>ICSharpCode.AvalonEdit.Document.TextDocument</code>.
 
133
Basically, the document is a <code>StringBuilder</code> with events.
 
134
However, the <code>Document</code> namespace also contains several features that are useful to applications working with the text editor.
 
135
 
 
136
<p>In the text editor, all three controls (<code>TextEditor</code>, <code>TextArea</code>, <code>TextView</code>) have a <code>Document</code> property pointing to the <code>TextDocument</code> instance.
 
137
You can change the <code>Document</code> property to bind the editor to another document. It is possible to bind two editor instances to the same document; you can use this feature to create a split view.
 
138
 
 
139
<p><i>Simplified</i> definition of <code>TextDocument</code>:
 
140
<pre lang="cs">public sealed class TextDocument : ITextSource
 
141
{
 
142
    public event EventHandler&lt;DocumentChangeEventArgs&gt; Changing;
 
143
    public event EventHandler&lt;DocumentChangeEventArgs&gt; Changed;
 
144
    public event EventHandler TextChanged;
 
145
 
 
146
    public IList&lt;DocumentLine&gt; Lines { get; }
 
147
    public DocumentLine GetLineByNumber(int number);
 
148
    public DocumentLine GetLineByOffset(int offset);
 
149
    public TextLocation GetLocation(int offset);
 
150
    public int GetOffset(int line, int column);
 
151
 
 
152
    public char GetCharAt(int offset);
 
153
    public string GetText(int offset, int length);
 
154
 
 
155
    public void Insert(int offset, string text);
 
156
    public void Remove(int offset, int length);
 
157
    public void Replace(int offset, int length, string text);
 
158
 
 
159
    public string Text { get; set; }
 
160
    public int LineCount { get; }
 
161
    public int TextLength { get; }
 
162
    public UndoStack UndoStack { get; }
 
163
}</pre>
 
164
 
 
165
In AvalonEdit, an index into the document is called an <b>offset</b>.
 
166
 
 
167
<p>Offsets usually represent the position between two characters.
 
168
The first offset at the start of the document is 0; the offset after the first <code>char</code> in the document is 1.
 
169
The last valid offset is <code>document.TextLength</code>, representing the end of the document.
 
170
This is exactly the same as the 'index' parameter used by methods in the .NET <code>String</code> or <code>StringBuilder</code> classes.
 
171
<p>
 
172
Offsets are easy to use, but sometimes you need Line / Column pairs instead.
 
173
AvalonEdit defines a <code>struct</code> called <code>TextLocation</code> for those.
 
174
 
 
175
<p>The document provides the methods <code>GetLocation</code> and <code>GetOffset</code> to convert between offsets and <code>TextLocation</code>s.
 
176
Those are convenience methods built on top of the <code>DocumentLine</code> class.
 
177
 
 
178
<p>The <code>TextDocument.Lines</code> collection contains one <code>DocumentLine</code> instance for every line in the document.
 
179
This collection is read-only to user code and is automatically updated to reflect the current document content.
 
180
 
 
181
<!------------------------------------------------------------>
 
182
<h2>Rendering: TextView</h2>
 
183
 
 
184
In the whole 'Document' section, there was no mention of extensibility.
 
185
The text rendering infrastructure now has to compensate for that by being completely extensible.
 
186
 
 
187
<p>The <code>ICSharpCode.AvalonEdit.Rendering.TextView</code> class is the heart of AvalonEdit.
 
188
It takes care of getting the document onto the screen.
 
189
 
 
190
<p>To do this in an extensible way, the <code>TextView</code> uses its own kind of model: the <code>VisualLine</code>.
 
191
Visual lines are created only for the visible part of the document.
 
192
<p>The rendering process looks like this:<br>
 
193
<img src="AvalonEdit/renderingPipeline.png" width="443" height="570" alt="rendering pipeline"/><br>
 
194
The last step in the pipeline is the conversion to one or more <code>System.Windows.Media.TextFormatting.TextLine</code> instances. WPF then takes care of the actual text rendering.
 
195
<p>
 
196
The "element generators", "line transformers" and "background renderers" are the extension points; it is possible to add custom implementations of
 
197
them to the <code>TextView</code> to implement additional features in the editor.
 
198
<!--
 
199
<p>
 
200
The extensibility features of the rendering namespace are discussed in detail in the article "AvalonEdit Rendering". (to be published soon)
 
201
-->
 
202
 
 
203
<h2>Editing: TextArea</h2>
 
204
 
 
205
The <code>TextArea</code> class is handling user input and executing the appropriate actions.
 
206
Both the caret and the selection are controlled by the <code>TextArea</code>.
 
207
<p>
 
208
You can customize the text area by modifying the <code>TextArea.DefaultInputHandler</code> by adding new or replacing existing
 
209
WPF input bindings in it. You can also set <code>TextArea.ActiveInputHandler</code> to something different than the default
 
210
to switch the text area into another mode. You could use this to implement an "incremental search" feature, or even a VI emulator.
 
211
<p>
 
212
The text area has the <code>LeftMargins</code> property &ndash; use it to add controls to the left of the text view that look like
 
213
they're inside the scroll viewer, but don't actually scroll. The <code>AbstractMargin</code> base class contains some useful code
 
214
to detect when the margin is attached/detaching from a text view; or when the active document changes. However, you're not forced to use it;
 
215
any <code>UIElement</code> can be used as margin.
 
216
 
 
217
<h2>Folding</h2>
 
218
Folding (code collapsing) is implemented as an extension to the editor.
 
219
It could have been implemented in a separate assembly without having to modify the AvalonEdit code.
 
220
A <code>VisualLineElementGenerator</code> takes care of the collapsed sections in the text document; and a custom margin draws the plus and minus
 
221
buttons.
 
222
<p>
 
223
You could use the relevant classes separately; but, to make it a bit easier to use, the static <code>FoldingManager.Install</code>
 
224
method will create and register the necessary parts automatically.
 
225
<p>
 
226
All that's left for you is to regularly call <code>FoldingManager.UpdateFoldings</code> with the list of foldings you want to provide.
 
227
You could calculate that list yourself, or you could use a built-in folding strategy to do it for you.
 
228
<p>
 
229
Here is the full code required to enable folding:
 
230
<pre lang="cs">foldingManager = FoldingManager.Install(textEditor.TextArea);
 
231
foldingStrategy = new XmlFoldingStrategy();
 
232
foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document);</pre>
 
233
If you want the folding markers to update when the text is changed, you have to repeat the <code>foldingStrategy.UpdateFoldings</code> call regularly.
 
234
<p>
 
235
Currently, only the <code>XmlFoldingStrategy</code> is built into AvalonEdit.
 
236
The sample application to this article also contains the <code>BraceFoldingStrategy</code> that folds using { and }.
 
237
However, it is a very simple implementation and does not handle { and } inside strings or comments correctly.
 
238
 
 
239
<h2>Syntax Highlighting</h2>
 
240
The highlighting engine in AvalonEdit is implemented in the class <code>DocumentHighlighter</code>.
 
241
Highlighting is the process of taking a <code>DocumentLine</code> and constructing a <code>HighlightedLine</code> instance for it
 
242
by assigning colors to different sections of the line.
 
243
<p>
 
244
The <code>HighlightingColorizer</code> class is the only link between highlighting and rendering. It uses a <code>DocumentHighlighter</code>
 
245
to implement a line transformer that applies the highlighting to the visual lines in the rendering process.
 
246
<p>
 
247
Except for this single call, syntax highlighting is independent from the rendering namespace.
 
248
To help with other potential uses of the highlighting engine, the <code>HighlightedLine</code> class has the method
 
249
<code>ToHtml</code> to produces syntax highlighted HTML source code.
 
250
<p>
 
251
The rules for the highlighting are defined using an "extensible syntax highlighting definition" (.xshd) file.
 
252
Here is a complete highlighting definition for a sub-set of C#:
 
253
<pre lang="xml">&lt;SyntaxDefinition name="C#"
 
254
        xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
 
255
    &lt;Color name="Comment" foreground="Green" />
 
256
    &lt;Color name="String" foreground="Blue" />
 
257
    
 
258
    &lt;!-- This is the main ruleset. -->
 
259
    &lt;RuleSet>
 
260
        &lt;Span color="Comment" begin="//" />
 
261
        &lt;Span color="Comment" multiline="true" begin="/\*" end="\*/" />
 
262
        
 
263
        &lt;Span color="String">
 
264
            &lt;Begin>"&lt;/Begin>
 
265
            &lt;End>"&lt;/End>
 
266
            &lt;RuleSet>
 
267
                &lt;!-- nested span for escape sequences -->
 
268
                &lt;Span begin="\\" end="." />
 
269
            &lt;/RuleSet>
 
270
        &lt;/Span>
 
271
        
 
272
        &lt;Keywords fontWeight="bold" foreground="Blue">
 
273
            &lt;Word>if&lt;/Word>
 
274
            &lt;Word>else&lt;/Word>
 
275
            &lt;!-- ... -->
 
276
        &lt;/Keywords>
 
277
        
 
278
        &lt;!-- Digits -->
 
279
        &lt;Rule foreground="DarkBlue">
 
280
            \b0[xX][0-9a-fA-F]+  # hex number
 
281
        |    \b
 
282
            (    \d+(\.[0-9]+)?   #number with optional floating point
 
283
            |    \.[0-9]+         #or just starting with floating point
 
284
            )
 
285
            ([eE][+-]?[0-9]+)? # optional exponent
 
286
        &lt;/Rule>
 
287
    &lt;/RuleSet>
 
288
&lt;/SyntaxDefinition></pre>
 
289
The highlighting engine works with "spans" and "rules" that each have a color assigned to them. In the XSHD format, colors can be both
 
290
referenced (<code>color="Comment"</code>) or directly specified (<code>fontWeight="bold" foreground="Blue"</code>).
 
291
<p>
 
292
Spans consist of two regular expressions (begin+end), while rules are simply a single RegEx with a color. The <code>&lt;Keywords></code> element is just a nice
 
293
syntax to define a highlighting rule that matches a set of words; internally a single RegEx will be used for the whole keyword list.
 
294
<p>
 
295
The highlighting engine works by first analyzing the spans: whenever a begin RegEx matches some text, that span is pushed onto a stack.
 
296
Whenever the end RegEx of the current span matches some text, the span is popped from the stack.
 
297
<p>
 
298
Each span has a nested rule set associated with it, which is empty by default.
 
299
This is why keywords won't be highlighted inside comments: the span's empty ruleset is active there, so the keyword rule is not applied.
 
300
<p>
 
301
This feature is also used in the string span: the nested span will match when a backslash is encountered, and the character following the backslash
 
302
will be consumed by the end RegEx of the nested span (<code>.</code> matches any character).
 
303
This ensures that <code>\"</code> does not denote the end of the string span; but <code>\\"</code> still does.
 
304
<p>
 
305
What's great about the highlighting engine is that it highlights only on-demand, works incrementally,
 
306
and yet usually requires only a few KB of memory even for large code files.
 
307
 
 
308
<p><i>On-demand</i> means that when a document is opened, only the lines initially visible will be highlighted. When the user scrolls down, highlighting will
 
309
continue from the point where it stopped the last time.
 
310
If the user scrolls quickly, so that the first visible line is far below the last highlighted line, then the highlighting engine still has to process all the
 
311
lines in between &ndash; there might be comment starts in them. However, it will only scan that region for changes in the span stack; highlighting rules will not
 
312
be tested.
 
313
<p>The stack of active spans is stored at the beginning of every line. If the user scrolls back up, the lines getting into view can be highlighted immediately
 
314
because the necessary context (the span stack) is still available.
 
315
<p><i>Incrementally</i> means that even if the document is changed, the stored span stacks will be reused as far as possible. If the user types <code>/*</code>, that would
 
316
theoretically cause the whole remainder of the file to become highlighted in the comment color. However, because the engine works on-demand, it will only update the
 
317
span stacks within the currently visible region and keep a notice 'the highlighting state is not consistent between line X and line X+1', where X is the last line 
 
318
in the visible region. Now, if the user would scroll down, the highlighting state would be updated and the 'not consistent' notice would be moved down.
 
319
But usually, the user will continue typing and type <code>*/</code> only a few lines later. Now the highlighting state in the visible region will revert to the
 
320
normal 'only the main ruleset is on the stack of active spans'. When the user now scrolls down below the line with the 'not consistent' marker;
 
321
the engine will notice that the old stack and the new stack are identical; and will remove the 'not consistent' marker. This allows reusing the stored span stacks
 
322
cached from before the user typed <code>/*</code>.
 
323
 
 
324
<p>While the stack of active spans might change frequently inside the lines, it rarely changes from the beginning of one line to the beginning of the next line.
 
325
With most languages, such changes happen only at the start and end of multiline comments. The highlighting engine exploits this property by storing
 
326
the list of span stacks in a special data structure (<code>ICSharpCode.AvalonEdit.Utils.CompressingTreeList</code>).
 
327
The memory usage of the highlighting engine is linear to the number of span stack changes; not to the total number of lines.
 
328
This allows the highlighting engine to store the span stacks for big code files using only a tiny amount of memory,
 
329
especially in languages like C# where sequences of <code>//</code> or <code>///</code> are more popular than <code>/* */</code> comments.
 
330
 
 
331
<h2>Code Completion</h2>
 
332
<p>AvalonEdit comes with a code completion drop down window.
 
333
You only have to handle the text entering events to determine when you want to show the window; all the UI is already done for you.
 
334
<p>
 
335
Here's how you can use it:
 
336
<pre lang="cs">    // in the constructor:
 
337
    textEditor.TextArea.TextEntering += textEditor_TextArea_TextEntering;
 
338
    textEditor.TextArea.TextEntered += textEditor_TextArea_TextEntered;
 
339
}
 
340
 
 
341
CompletionWindow completionWindow;
 
342
 
 
343
void textEditor_TextArea_TextEntered(object sender, TextCompositionEventArgs e)
 
344
{
 
345
    if (e.Text == ".") {
 
346
        // Open code completion after the user has pressed dot:
 
347
        completionWindow = new CompletionWindow(textEditor.TextArea);
 
348
        IList&lt;ICompletionData> data = completionWindow.CompletionList.CompletionData;
 
349
        data.Add(new MyCompletionData("Item1"));
 
350
        data.Add(new MyCompletionData("Item2"));
 
351
        data.Add(new MyCompletionData("Item3"));
 
352
        completionWindow.Show();
 
353
        completionWindow.Closed += delegate {
 
354
            completionWindow = null;
 
355
        };
 
356
    }
 
357
}
 
358
 
 
359
void textEditor_TextArea_TextEntering(object sender, TextCompositionEventArgs e)
 
360
{
 
361
    if (e.Text.Length > 0 &amp;&amp; completionWindow != null) {
 
362
        if (!char.IsLetterOrDigit(e.Text[0])) {
 
363
            // Whenever a non-letter is typed while the completion window is open,
 
364
            // insert the currently selected element.
 
365
            completionWindow.CompletionList.RequestInsertion(e);
 
366
        }
 
367
    }
 
368
    // Do not set e.Handled=true.
 
369
    // We still want to insert the character that was typed.
 
370
}</pre>
 
371
This code will open the code completion window whenever '.' is pressed.
 
372
By default, the <code>CompletionWindow</code> only handles key presses like Tab and Enter to insert the currently selected item. To also make
 
373
it complete when keys like '.' or ';' are pressed, we attach another handler to the <code>TextEntering</code> event and tell the
 
374
completion window to insert the selected item.
 
375
<p>
 
376
The <code>CompletionWindow</code> will actually never have focus - instead, it hijacks the WPF keyboard input events
 
377
on the text area and passes them through its <code>ListBox</code>.
 
378
This allows selecting entries in the completion list using the keyboard and normal typing in the editor at the same time.
 
379
<p>For the sake of completeness, here is the implementation of the <code>MyCompletionData</code> class used in the code above:
 
380
<pre lang="cs">/// Implements AvalonEdit ICompletionData interface to provide the entries in the
 
381
/// completion drop down.
 
382
public class MyCompletionData : ICompletionData
 
383
{
 
384
    public MyCompletionData(string text)
 
385
    {
 
386
        this.Text = text;
 
387
    }
 
388
    
 
389
    public System.Windows.Media.ImageSource Image {
 
390
        get { return null; }
 
391
    }
 
392
    
 
393
    public string Text { get; private set; }
 
394
    
 
395
    // Use this property if you want to show a fancy UIElement in the list.
 
396
    public object Content {
 
397
        get { return this.Text; }
 
398
    }
 
399
    
 
400
    public object Description {
 
401
        get { return "Description for " + this.Text; }
 
402
    }
 
403
    
 
404
    public void Complete(TextArea textArea, ISegment completionSegment,
 
405
        EventArgs insertionRequestEventArgs)
 
406
    {
 
407
        textArea.Document.Replace(completionSegment, this.Text);
 
408
    }
 
409
}</pre>
 
410
Both the content and the description shown may be any content acceptable in WPF, including custom UIElements.
 
411
You may also implement custom logic in the <code>Complete</code> method if you want to do more than simply inserting the text.
 
412
The <code>insertionRequestEventArgs</code> can help decide which kind of insertion the user wants - depending on how the insertion
 
413
was triggered, it is an instance of <code>TextCompositionEventArgs</code>, <code>KeyEventArgs</code> or <code>MouseEventArgs</code>.
 
414
 
 
415
<h2>History</h2>
 
416
 
 
417
<ul>
 
418
<li>August 13, 2008: Work on AvalonEdit started</li>
 
419
<li>November 7, 2008: First version of AvalonEdit added to SharpDevelop 4.0 trunk</li>
 
420
<li>June 14, 2009: The SharpDevelop team switches to SharpDevelop 4 as their IDE for working on SharpDevelop; AvalonEdit starts to get used for real work</li>
 
421
<li>October 4, 2009: This article first published on The Code Project</li>
 
422
</ul>
 
423
 
 
424
<p><b>Note: although my sample code is provided under the MIT license, ICSharpCode.AvalonEdit itself is provided under the terms of the GNU LGPL.</b>
 
425
 
 
426
<!-------------------------------    That's it!   --------------------------->
 
427
</div></body>
 
428
 
 
429
</html>