使用ICSharpCode.TextEditor制作一个语法高亮显示的XML编辑器

品高工作流 的流程模拟器中使用了一个具有语法高亮和折叠功能的XML编辑器,其核心就是用了SharpDevelop中的ICSharpCode.TextEditor控件,如下图所示:

SharpDevelop的源代码中有一个功能丰富,支持语法高亮,代码折叠的文本编辑器控件(位置:\SharpDevelop\src\Libraries\ICSharpCode.TextEditor)。本文附件的Demo工程中将演示如何加载和保存文件,查找和替换文本中的字符串,执行剪贴板操作,使用TextMarkers来高亮突出显示字符串,使用FoldingStrategy让文本可以折叠,支持使用书签,并通过改变一些显示属性设置更方便我们进行文本编辑。

希望本文有足够的信息来帮助你知道如何编写文本编辑器中其他你想要的功能。

一、ICSharpCode.TextEditor的设计

该文本编辑器实际上包含三个彼此紧密结合的内部控件:

  • 在最顶层是TextEditorControl,它包含一个或者两个TextAreaControl。当分割窗口时它有两个TextEditorControl,如上面的截图所示。
  • TextAreaControl封装了水平和垂直滚动条以及一个TextArea 。
  • TextArea是真正获得焦点之后的控件。它用于绘制文本以及处理键盘输入。

比这些控件类都重要的是IDocument接口。DefaultDocument类实现了IDocument接口,该接口提供了访问SharpDevelop文本编辑器的大多数特性:undo/redo,标记(Markers),书签,代码折叠,自动缩进,语法高亮显示,属性设置以及管理文本缓冲区。

以下是这些基本类的类图:

二、详情

下图是一个更完整的类图,其中包括通过TextArea和IDocument的属性所能访问的其他的类和接口。文本编辑器的语法高亮和代码折叠被划分为单独的类或接口,如果你需要,它们中的大部分可以被自定义或派生版本的类或者接口所取代。

TextEditor(和SharpDevelop一样)经常使用策略模式,所以你会在很多地方看到Strategy。在策略模式中,一个接口的定义是根据功能需要,但并不实现这些功能。如果你需要不同的功能实现,你可以写一个实现了IDocument接口的新策略。由于某些原因,MarkerStrategy是一个sealed接口类,没有实现相应的接口,因此它不能被替换掉。

让我们来看看IDocument的特性:

1.  该编辑器自动提供无限次的undo/redo。你不需要做任何特别的编程去实现undo功能;只是一定要使用IDocument接口中的方法,而不是使用ITextBufferStrategy中的方法 (后者绕过undo堆栈)。你可以将多个文本操作合在一起,将它们包含在IDocument.UndoStack.StartUndoGroup()和IDocument.UndoStack.EndUndoGroup()之间,这样就可以通过一个undo命令来撤销这些操作。

2.  标记(Markers)(TextMarker类的实例)表示一段文本的范围(包括开始和结束位置)。在通过文档的MarkerStrategy注册一个标记之后,当文档中的文本被修改之后,这个注册标记的开始和结束位置会自动移动。标记(Markers)可以是可见或不可见的;若可见,一个标记可以显示文本的拼写检查风格的波浪型下划线,或者高亮显示一个标记所覆盖的区域。本文的Demo应用程序使用标记来实现查找功能中的“查找全部并高亮显示”命令。

奇怪的是,还有一个类也可以达到类似的目的: TextAnchor可以锚到一个点,并根据文档的更改而自动移动,但是你却不能使用这个类,因为它的构造函数是internal的。

3.  书签是显示在编辑器左边图标栏的矩形标记,用户可以通过按F2键在矩形标记中转换。本文Demo工程中实现了切换书签以及在它们之间前后移动的功能。

4.  代码折叠允许文本块被收起来。ISharpCode.TextEditor中没有内建的代码折叠策略,所以你如果需要制作一个支持代码折叠的文本编辑器,可以考虑研究SharpDevelop的源代码来实现一个代码折叠策略类。在本文的Demo中,使用了SharpDevelop源代码中的XmlFoldingStrategy类用来支持XML文本的折叠。DefaultDocument和TextEditorControl并不会自动更新代码折叠标记,所以在本文的Demo中,折叠会在程序初始化的时候以及在文件加载后更新。

在代码折叠的显示中,有两种类型的行号。

²  逻辑行号是指是显示在左边图标栏中的真实行号。

²  可见行号则是应用代码折叠后所显示的行号。可见行号本身的号码来源于逻辑行号。

5.  自动缩进由继承了IFormattingStrategy接口的类来提供支持,当用户有输入时,自动缩进会自动格式化编辑器中的文本。DefaultFormattingStrategy实现了当Enter键被按下时根据上一行来自动缩进的简单功能。在 SharpDevelop的源代码中你可以找到更多的缩进策略。

IFormattingStrategy接口中定义了包括向后搜索或者向前搜索匹配条件文本的方法以使结果能够高亮显示,实现该接口的类有:TextUtilities,BracketHighlightingSheme,BracketHighlight和TextArea。TextArea中通过硬编码来实现 ()、[]和{}等括号的自动缩进。

6.  语法高亮通常是由一个DefaultHighlightingStrategy类的实例来提供支持,它使用以”xshd”为扩展名的 XML文件来高亮显示各种文本。有超过十个这样的XML文件作为资源嵌入在文本编辑器DLL中,当加载一个文件时,TextEditorControl类会根据文件的扩展名来自动选择一个高亮规则文件。修改编辑器中的文本文件的名称并不会改变之前选择的高亮规则,所以本文Demo中的大部分都是手动设置语法高亮规则的。网上有很多关于如何添加基于XSHD高亮规则的文章,如:这里 和 这里

7.  文本缓冲区策略用来管理文本缓冲区。默认的GapTextBufferStrategy类的算法在维基百科上有描述以及在CodeProject上也有。

8.  ITextEditorProperties接口中封装了多个属性设置选项,如:是否显示行号和制表符显示几个字符宽等属性。

ITextEditorProperties没有任何方式去通知其他的对象其属性已被更改。如果你更改了其中的一个属性,将直接影响到编辑器控件的显示,编辑器控件也不会自动重新绘制。由于这样,TextEditorControlBase将ITextEditorProperties的每个需要监管的属性都进行了封装。例如:TextEditorControlBase.TabIndent是包装了ITextEditorProperties.TabIndent。顺便说一下,你可以共享一个ITextEditorProperties实例对象给许多文本编辑器控件使用。

除了这些,在ICSharpCode.TextEditor项目还包括被称为"智能感知"的相关代码:用于在编辑器内部弹出一个列表框用来显示标识符和已有的方法。

ICSharpCode.TextEditor本身并没有实际执行智能感知代码,但它包含支持这种功能的图形界面的代码。但是,这些代码不能直接被文本编辑器使用,本文只是一个XML编辑器,并不涉及代码自动完成。

文本编辑器中源代码中包含了许多的类;一些类可能不适合显示在类图之上,在本文中并没有涉及到它们。比如说TextWord,用作语法高亮显示的基本单元;LineManager则是被DefaultDocument类用来转换"offsets" 为"positions";还有TextUtilities,一个静态的方法集合类。

三、更多细节:

•    文档的位置可以用两种方式表示。首先,一个文档的位置可以用行列方式来表示,在TextLocation结构中可以找到它们。其实一个文档就是一个字符数组,它的长度为IDocument.TextLength。该字符数组的索引叫做偏移量(offset 类型:int)。偏移量在ICSharpCode.TextEditor中被普遍使用,但有一些类(例如SelectionManager)则使用Location来表示文档的位置,例如TextLocation。你可以使用IDocument.OffsetToPosition和IDocument.PositionToOffset将Location和Offset这两种方式互相转换。

•    Caret表示闪烁的光标。你可以移动光标改变Caret的Line ,Column ,或Position的属性。

•    所有文本编辑器的动作Action,都可以在SharpDevelop中通过组合键来调用,它们都被封装在继承了ICSharpCode.TextEditor.Actions.IEditAction接口的类中 。其中的一部分Action在本文的Demo工程的编辑菜单栏中会被使用到。

•    在TextArea左边显示了三个边空,上面的类图中并没有它们。它们不是单独的控件,但TextArea通过鼠标和绘制来控制它们。

²  FoldMargin显示代码折叠的+或者-符号的图标,如果你不使用代码折叠,恐怕是没有办法来它(当然,你可以更改源代码了)。

²  IconBarMargin显示图标,如书签(或SharpDevelop中断点)。它的可见性是受ITextEditorProperties.IsIconBarVisible控制。

²  GutterMargin显示行号。可见性是受ITextEditorProperties.ShowLineNumbers控制。

•    ICSharpCode.TextEditor中最重量级的部分就是它的语法高亮,使用了大约正在编辑文本文件10倍大小的内存。它绘制这些文本使用了大量的CPU资源以及在内存中分配了大量的临时对象。

•    更多细节请自行研究ICSharpCode.TextEditor的源代码,本文的附件Demo中将提供一些最基本的功能实现。

•   本文大部分代码及文章翻译来源: CodeProject: Using ICSharpCode.TextEditor 特别感谢原作者:Qwertie

•    本文的Demo源代码:Bingosoft.Workflow.XmlPad.rar

使用ICSharpCode.TextEditor制作一个语法高亮显示的XML编辑器的更多相关文章

  1. ICSharpCode.TextEditor使用及扩展

    SharpDevelop (#develop)有很多“副产品”,其中最出名的应算SharpZipLib (#ziplib),纯C#的ZIP类库,而在SharpDevelop (#develop)中,“ ...

  2. [vim]设置vim语法高亮显示和自动缩进

    1.配置文件的位置        在目录 /etc/vim下面,有个名为vimrc的文件,这是系统中公共的vim配置文件,对所有用户都有效.而在每个用户的主目录下,都可以自己建立私有的配置文件,命名为 ...

  3. ICSharpCode.TextEditor如何自定义代码折叠和高亮

    ICSharpCode.TextEditor 是一款非常不错的.NET代码编辑控件,内置了多种高亮语言支持,同时完美支持中文,非常赞!先来看一下运行效果: 1 项目结构 这里需要注意lib文件夹下导入 ...

  4. 【前端】向blog或网站中添加语法高亮显示代码方法总结

    向blog或网站中添加语法高亮显示的代码方法总结 文章目录 预备知识 目标 第一类方法:嵌入 第二类方法:外部引用 第三类方法:忽略HTML和PHP 最近在写代码时遇到一个问题,就是如何让代码像在ID ...

  5. 用JS制作一个信息管理平台完整版

      前  言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容.   1.JSON的基础知识 ...

  6. TensorFlow练习13: 制作一个简单的聊天机器人

    现在很多卖货公司都使用聊天机器人充当客服人员,许多科技巨头也纷纷推出各自的聊天助手,如苹果Siri.Google Now.Amazon Alexa.微软小冰等等.前不久有一个视频比较了Google N ...

  7. Word文档中的语法高亮显示代码

    有时候我们程序员也需要在word文档里面显示代码,但是直接复制过去 不好看,格式也不太对,这里给大家分享一个Word文档中的语法高亮显示代码的方法 http://www.planetb.ca/synt ...

  8. 用 Python 制作一个艺术签名小工具,给自己设计一个优雅的签名

    生活中有很多场景都需要我们签字(签名),如果是一些不重要的场景,我们的签名好坏基本无所谓了,但如果是一些比较重要的场景,如果我们的签名比较差的话,就有可能给别人留下不太好的印象了,俗话说字如其人嘛,本 ...

  9. 使用CocosSharp制作一个游戏 - CocosSharp中文教程

    注:本教程翻译自官方<Walkthrough - Building a game with CocosSharp>,官方教程有很多地方说的不够详细,或者代码不全,导致无法继续,本人在看了G ...

随机推荐

  1. C#中this的作用

    一.C# this指针的几种用法 1.限定被相似的名称隐藏的成员   C# 代码   复制 public class ThisName { public string name = "张三& ...

  2. PHP免费的空间www.hostinger.co.uk

    免费的PHP空间:http://hostinger.co.uk hostinger是一个免费的PHP空间,不仅100%完全免费而且还没有广告,提供2G物理空间和100GMysql空间 可以一键安装Wo ...

  3. WCF 之 消息契约(MessageContract)

    对于SOAP来说主要由两部分构成Header和Body,他们两个共同构成了SOAP的信封,通常来说Body保存具体的数据内容,Header保存一些上下文信息或关键信息. 比如:在一些情况下,具有这样的 ...

  4. FFMPEG中最要害的结构体之间的关系

    FFMPEG中最关键的结构体之间的关系 http://www.myexception.cn/program/1404591.html FFMPEG中结构体很多.最关键的结构体可以分成以下几类: a)  ...

  5. synchronized探究

    synchronized的加锁方式 synchronized的本质是给对象上锁,对象包括实例对象,也包括类对象.常见的加锁方式有下面几种写法:(1)在非static方法上加synchronized,例 ...

  6. java在线预览txt、word、ppt、execel,pdf代码

    在页面上显示各种文档中的内容.在servlet中的逻辑 word: BufferedInputStream bis = null; URL url = null; HttpURLConnection ...

  7. Jni中图片传递的3种方式(转)

    java层的图片如何传递到c/c+层处理,处理完之后如何传回java层,下面总结了一下用到的三种方法. 1.将Bitmap转为int[]数组对象,将数组作为参数传递到C/C++层,处理完之后再以int ...

  8. UIScrollView 循环滚动,代码超简单

    如今非常多应用里面多多少少都用到了循环滚动,要么是图片.要么是view,或者是其它,我总结一下,写了个demo分享给大家. 先看代码之后在讲原理: 1.创建一个空的项目(这个我就不多说了). 2.加入 ...

  9. Java lock 能被中断, synchronized 不能被中断

    1.lock是可中断锁,而synchronized 不是可中断锁 线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定, 如果使用 synchronized ,如果A不释放, ...

  10. 推荐10款最常用的Android开发工具

    我们使用各种语言进行开发时,总是会用到各种各样的开发工具.有些开发工具是开发人员的必备品,有些则是为了提高开发效率而用.Android开发同样也会用到多种开发工具,供开发人员设计.创建.测试和发布程序 ...