AvalonEdit的最新版本是SharpDevelop项目的一部分。有关AvalonEdit的详细信息,请访问www.avalonedit.net. 介绍 ICSharpCode。AvalonEdit是一个基于wpf的文本编辑器,是我为SharpDevelop 4.0编写的。它是用来替代ICSharpCode的。TextEditor,但应该是: 可扩展,易于使用,更擅长处理大型文件 可扩展的意思是我希望锐化开发插件能够添加功能到文本编辑器。例如,一个插件应该允许在注释中插入图片——这样,你就可以把类图这样的东西直接放到源代码中! 容易使用,我指的是编程API。它应该只是工作™。例如,这意味着如果更改文档文本,编辑器应该自动重新绘制,而不必调用Invalidate()。而且,如果你做错了什么,你应该得到一个有意义的异常,而不是损坏状态,然后崩溃在一个不相关的位置。 更好地处理大文件意味着编辑器应该能够处理大文件(例如mscorlib XML文档文件,7mb, 74100 LOC),即使启用了像折叠(代码崩溃)这样的特性。 使用的代码 编辑器的主要类是ICSharpCode.AvalonEdit.TextEditor。你可以使用它就像一个普通的WPF文本框: 隐藏,复制Code
<avalonEdit:TextEditorxmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"Name="textEditor"FontFamily="Consolas"SyntaxHighlighting="C#"FontSize="10pt"/>
AvalonEdit内置了语法高亮显示定义:NET, Boo, Coco/R语法,c++, c#, HTML, Java, JavaScript,补丁文件,PHP, TeX, VB和XML。 如果您需要更多的AvalonEdit,而不仅仅是一个语法高亮显示的简单文本框,那么您首先必须了解更多关于AvalonEdit的架构。 体系结构 正如您在这个依赖关系图中看到的,AvalonEdit由几个子名称空间组成,它们有干净地分隔的作业。大多数名称空间都有一种“main”类。 ICSharpCode.AvalonEdit。各种实用工具类。文本模型ICSharpCode.AvalonEdit。可扩展的视图到文档ICSharpCode.AvalonEdit。控制文本编辑(例如,插入符号,选择,处理用户输入)。允许代码崩溃ICSharpCode.AvalonEdit。高亮:HighlightingManager -高亮引擎icsharpcode . avalonedit .高亮。XML语法高亮显示定义支持。ICSharpCode.AvalonEdit xshd文件)。显示代码完成的下拉列表。AvalonEdit: TextEditor -主要的控制,把它一起 这是TextEditor控件的可视化树: 理解AvalonEdit是一个具有三层的复合控件是很重要的:TextEditor(主控件),TextArea(编辑),TextView(渲染)。虽然主控件为常见任务提供了一些方便的方法,但对于大多数高级特性,您必须直接使用内部控件。你可以使用textEditor访问它们。或textEditor.TextArea.TextView文本区域。 文档(文本模型) 模型的主要类是ICSharpCode.AvalonEdit.Document.TextDocument。基本上,文档是一个带有事件的StringBuilder。但是,文档名称空间还包含一些对使用文本编辑器的应用程序有用的特性。 在文本编辑器中,所有三个控件(TextEditor, TextArea, TextView)都有一个指向TextDocument实例的文档属性。您可以更改文档属性,以将编辑器绑定到另一个文档。可以将两个编辑器实例绑定到同一个文档;您可以使用此特性创建分屏视图。 以下是简化后的TextDocument定义: 隐藏,复制Code
public sealed class TextDocument : ITextSource { public event EventHandler<DocumentChangeEventArgs> Changing; public event EventHandler<DocumentChangeEventArgs> Changed; public event EventHandler TextChanged; public IList<DocumentLine> Lines { get; } public DocumentLine GetLineByNumber(int number); public DocumentLine GetLineByOffset(int offset); public TextLocation GetLocation(int offset); public int GetOffset(int line, int column); public char GetCharAt(int offset); public string GetText(int offset, int length); public void Insert(int offset, string text); public void Remove(int offset, int length); public void Replace(int offset, int length, string text); public string Text { get; set; } public int LineCount { get; } public int TextLength { get; } public UndoStack UndoStack { get; } }
在AvalonEdit中,进入文档的索引称为偏移量。 偏移量通常表示两个字符之间的位置。文档开始处的第一个偏移量为0;文档中第一个字符之后的偏移量为1。最后一个有效偏移量是document。文本长度,表示文档的结束。这与。net字符串或StringBuilder类中方法使用的“index”参数完全相同。 偏移量很容易使用,但有时您需要行/列对来代替。AvalonEdit为这些定义了一个名为TextLocation的结构。 该文档提供方法GetLocation和GetOffset,以便在偏移量和textlocation之间进行转换。这些都是建立在DocumentLine类之上的便利方法。 TextDocument。Lines集合为文档中的每一行包含一个DocumentLine实例。此集合对用户代码是只读的,并会自动更新以反映当前文档内容。 呈现 在整个“文档”部分中,没有提到可扩展性。文本呈现基础设施现在必须通过完全可扩展来弥补这一点。 ICSharpCode.AvalonEdit.Rendering。TextView类是heart AvalonEdit。它负责将文档显示在屏幕上。 为了以一种可扩展的方式做到这一点,TextView使用了它自己的一种模型:VisualLine。只为文档的可见部分创建可视线条。 渲染过程是这样的: 管道中的最后一步是转换到一个或多个System.Windows.Media.TextFormatting。TextLine实例。然后WPF负责实际的文本渲染。 “元素生成器”、“线路转换器”和“背景渲染器”是扩展点;可以在编辑器中添加他们的自定义实现到TextView来实现额外的功能。 编辑 TextArea类处理用户输入并执行适当的操作。插入符号和选择内容都由文本区域控制。 您可以通过修改文本区域来定制文本区域。DefaultInputHandler通过在其中添加新的或替换现有的WPF输入绑定。你也可以设置文本区域。ActiveInputHandler切换到与默认值不同的值,以将文本区域切换到另一种模式。您可以使用它来实现“增量搜索”特性,甚至一个VI仿真器。 文本区域有LeftMargins属性——使用它将控件添加到文本视图的左侧,这些控件看起来像是在滚动查看器中,但实际上并不滚动。AbstractMargin基类包含一些有用的代码,用于检测边框何时从文本视图附加/分离;或活动文档更改时。然而,你并不是被迫使用它;任何UIElement都可以用作边距。 折叠 折叠(代码折叠)是作为编辑器的扩展实现的。它可以在单独的程序集中实现,而不必修改AvalonEdit代码。VisualLineElementGenerator负责处理文本文档中的折叠部分,而自定义边框绘制加号和减号按钮。 您可以单独使用相关的类;但是,为了让它更容易使用,静态FoldingManager。安装方法将自动创建和注册所需的部件。 剩下要做的就是定期调用FoldingManager。使用要提供的折叠列表进行更新。你可以自己计算这个列表,或者你可以使用一个内置的折叠策略来帮你完成。 以下是启用折叠所需的完整代码: 隐藏,复制Code
foldingManager = FoldingManager.Install(textEditor.TextArea);
foldingStrategy = new XmlFoldingStrategy();
foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document);
如果您希望在文本更改时更新折叠标记,则必须重复折叠策略。UpdateFoldings定期调用。 目前,只有XmlFoldingStrategy内置于AvalonEdit中。本文的示例应用程序还包含使用{和}进行折叠的BraceFoldingStrategy。但是,它是一个非常简单的实现,不能正确处理字符串或注释中的{和}。 语法高亮显示 AvalonEdit中的高亮显示引擎是在类documententhighlighter中实现的。高亮显示是采用DocumentLine并通过为该行的不同部分分配颜色为其构造HighlightedLine实例的过程。 HighlightingColorizer类是高亮显示和呈现之间的唯一链接。它使用了一个documententhighlighter来实现一个行转换器,该转换器在渲染过程中将高亮显示应用到可视的线条上。 除了这个调用之外,语法突出显示独立于呈现的名称空间。为了帮助突出显示引擎的其他潜在用途,HighlightedLine类具有ToHtml方法来生成语法突出显示的HTML源代码。 突出显示规则是使用“可扩展语法突出显示定义”(.xshd)文件定义的。以下是c#子集的完整高亮定义: 隐藏,收缩,复制Code
<SyntaxDefinitionname="C#"xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008"> <Colorname="Comment"foreground="Green"/> <Colorname="String"foreground="Blue"/> <!-- This is the main ruleset. --> <RuleSet> <Spancolor="Comment"begin="//"/> <Spancolor="Comment"multiline="true"begin="/*"end="*/"/> <Spancolor="String"> <Begin>"</Begin> <End>"</End> <RuleSet> <!-- nested span for escape sequences --> <Spanbegin="\"end="."/> </RuleSet> </Span> <KeywordsfontWeight="bold"foreground="Blue"> <Word>if</Word> <Word>else</Word> <!-- ... --> </Keywords> <!-- Digits --> <Ruleforeground="DarkBlue"> 0[xX][0-9a-fA-F]+ # hex number | ( d+(.[0-9]+)? #number with optional floating point | .[0-9]+ #or just starting with floating point ) ([eE][+-]?[0-9]+)? # optional exponent </Rule> </RuleSet> </SyntaxDefinition>
突出显示引擎与“span”和“rules”一起工作,每个“span”和“rules”都有指定的颜色。在XSHD格式中,颜色可以被引用(color="Comment"),也可以被直接指定(fontWeight="bold" foreground="Blue")。 span由两个正则表达式组成(begin+end);而规则只是带有颜色的单个正则表达式。& lt; Keywords>元素只是一个很好的语法,用来定义匹配一组单词的高亮显示规则;在内部,单个正则表达式将用于整个关键字列表。 突出显示引擎首先分析span:每当begin regex匹配某些文本时,该span就被推到堆栈上。只要当前span的结束正则表达式匹配某些文本,就会从堆栈中弹出span。 每个span都有一个与之关联的嵌套规则集,默认情况下为空。这就是为什么关键字不会在注释内突出显示:span的空规则集在那里是活动的,因此关键字规则不会被应用。 这个特性也用于字符串span中:当遇到反斜杠时,嵌套的span将匹配,后面的字符将被嵌套的span(的结束正则表达式使用。匹配任何字符)。这确保" does不是表示弦跨度的末端;但是“\”仍然存在。 高亮显示引擎的伟大之处在于,它只按需高亮显示,以增量方式工作,但即使对于大型代码文件,通常也只需要几个KB的内存。 按需意味着当一个文档被打开时,只有最初可见的行会被突出显示。当用户向下滚动时,高亮显示将从上次停止的位置继续。如果用户快速滚动,以至于第一个可见的行远远低于最后一个突出显示的行,那么突出显示引擎仍然必须处理中间的所有行——其中可能有注释开始。但是,它将只扫描该区域以查看span堆栈中的更改;高亮显示规则将不会被测试。 活动跨越的堆栈存储在每一行的开头。如果用户向上滚动,进入视图的行可以立即突出显示,因为必要的上下文(span堆栈)仍然可用。 递增的意思是,即使文档发生了更改,存储的span堆栈也将尽可能重用。如果用户键入/*,从理论上讲,这将导致整个文件的其余部分以注释的颜色突出显示。但是,因为引擎是按需工作的,它将只更新当前可见区域内的span堆栈,并保持“高亮显示状态在X行和X+1行之间不一致”的通知,其中X是可见区域的最后一行。现在,如果用户向下滚动,高亮显示状态就会更新,“不一致”的通知就会向下移动。但通常情况下,用户会继续输入,然后只在几行之后输入*/。现在,可见区域的高亮显示状态将恢复为正常的“只有主规则集在活动span的堆栈上”。当用户现在滚动到带有“不一致”标记的行以下时,引擎将注意到旧堆栈和新堆栈是相同的,并将删除“不一致”标记。这允许重用在用户键入/*之前缓存的存储span堆栈。 尽管活动跨越的堆栈可能在行内频繁变化,但从一行的开头到下一行的开头很少变化。对于大多数语言,这样的更改只发生在多行注释的开始和结束处。突出显示引擎通过将span堆栈列表存储在一个特殊的数据结构(ICSharpCode.AvalonEdit.Utils.CompressingTreeList)来利用这个属性。突出显示引擎的内存使用量与跨度堆栈变化的数量成线性关系;而不是总行数。这允许突出显示引擎仅使用少量内存就可以存储大代码文件的span堆栈,特别是在像c#这样的语言中,//或///序列比/* */注释更流行。 代码自动完成 AvalonEdit带有一个代码完成下拉窗口。你只需要处理文本输入事件,以确定何时你想要显示窗口;所有UI都已经为您完成了。 以下是如何使用它: 隐藏,收缩,复制Code
// in the constructor: textEditor.TextArea.TextEntering += textEditor_TextArea_TextEntering; textEditor.TextArea.TextEntered += textEditor_TextArea_TextEntered; } CompletionWindow completionWindow; void textEditor_TextArea_TextEntered(object sender, TextCompositionEventArgs e) { if (e.Text == ".") { // Open code completion after the user has pressed dot: completionWindow = new CompletionWindow(textEditor.TextArea); IList<ICompletionData> data = completionWindow.CompletionList.CompletionData; data.Add(new MyCompletionData("Item1")); data.Add(new MyCompletionData("Item2")); data.Add(new MyCompletionData("Item3")); completionWindow.Show(); completionWindow.Closed += delegate { completionWindow = null; }; } } void textEditor_TextArea_TextEntering(object sender, TextCompositionEventArgs e) { if (e.Text.Length > 0 && completionWindow != null) { if (!char.IsLetterOrDigit(e.Text[0])) { // Whenever a non-letter is typed while the completion window is open, // insert the currently selected element. completionWindow.CompletionList.RequestInsertion(e); } } // Do not set e.Handled=true. // We still want to insert the character that was typed. }
这段代码将打开代码完成窗口。”。默认情况下,CompletionWindow只处理按Tab键和Enter键来插入当前选择的项目。当键像'时也要使它完整。'或';',我们附加另一个处理程序到TextEntering事件,并告诉完成窗口插入选定的项目。 CompletionWindow实际上不会有焦点-相反,它劫持WPF键盘输入事件在文本区域,并通过它的列表框传递。这允许同时使用键盘和编辑器中的常规输入选择完成列表中的条目。 为了完整性,这里是实现MyCompletionData类使用在上面的代码: 隐藏,收缩,复制Code
/// Implements AvalonEdit ICompletionData interface to provide the entries in the /// completion drop down. public class MyCompletionData : ICompletionData { public MyCompletionData(string text) { this.Text = text; } public System.Windows.Media.ImageSource Image { get { return null; } } public string Text { get; private set; } // Use this property if you want to show a fancy UIElement in the list. public object Content { get { return this.Text; } } public object Description { get { return "Description for " + this.Text; } } public void Complete(TextArea textArea, ISegment completionSegment, EventArgs insertionRequestEventArgs) { textArea.Document.Replace(completionSegment, this.Text); } }
显示的内容和描述都可以是WPF中可以接受的任何内容,包括定制的uielement。除了简单地插入文本之外,还可以在完整方法中实现自定义逻辑。insertionRequestEventArgs可以帮助决定用户想要的插入类型——取决于插入是如何被触发的,它是TextCompositionEventArgs、KeyEventArgs或MouseEventArgs的实例。 历史 2008年6月14日:夏普开发团队切换到夏普开发4作为他们开发夏普开发的IDE;AvalonEdit开始得到真正用于workOctober 4, 2009:本文首先发表在代码ProjectJune 13, 2010:更新下载AvalonEdit 4.0.0.5950 (SharpDevelop 4.0 Beta 1) 9月13日,2011:更新下载AvalonEdit 4.1.0.7916 (SharpDevelop 4.1 RC),大量的bug修复,改善Performance 现在针对。net 4.0, 5月12日2012:更新下载AvalonEdit 4.2.0.8783 (SharpDevelop 4.2),添加SearchPanel添加支持虚拟space 一些bugfixesMarch 3, 2013:更新下载AvalonEdit 4.3.0.9390 (SharpDevelop 4.3)添加支持输入法编辑器(IME)固定的一个主要缺陷,有时造成“InvalidOperationException:试图建立视觉线从倒塌的线”当更新现有的褶皱。2013年4月2日:更新下载AvalonEdit 4.3.1.9430 (SharpDevelop 4.3.1)修复了一个IME支持上的错误——如果它被另一个WPF控件禁用,上一个版本就不能正确地重新启用IME。 注意:虽然我的示例代码是根据MIT许可提供的,但是ICSharpCode。AvalonEdit本身是根据GNU LGPL. 本文转载于:http://www.diyabc.com/frontweb/news382.html