扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
这样应用程序动态的创建了AllElements类型并实例化了一个对象引用,这时VB.NET脚本程序就可以直接使用 document.all.文档元素对象名称 来直接访问文档中特定内容了。注意当文档内容发生改变时需要重新生成AllElements的类型并实例化。
以上的程序模块建好后就可以搭建VB.NET脚本语言运行环境了,首先定义类型TextDocumentVsaSite来实现IVsaSite接口,实现其中的GetGlobalInstance函数,该函数参数为字符串,返回一个对象,该函数实际上判断若参数"document"则返回文档对象TextDocument ,若参数为"eventobj"则返回刚刚定义了事件对象,若为"dbconnection"则返回数据库连接对象。该对象还实现了IVsaSite.OnCompilerError来处理脚本编译错误。
程序还从Microsoft.VisualBasic.Vsa.VsaEngine派生了脚本引擎VBScriptEngine。该模块使用VsaEngine的Items.CreateItem来向引擎添加document,eventobj,dbconnection等全局变量,还添加一些所需的.NET引用,此外还实现了对脚本代码文本的一些处理,比如加密,自动添加某些必须的代码等。
脚本环境还模拟实现了文档事件的处理,比如文档中某些元素对象支持onchange事件,这些元素是有名称的,当用户修改这些元素的内容时,程序会查询脚本引擎来看是否存在名为对象名称_OnChange的过程存在,若存在则执行它,这样就模拟实现了事件处理。
在VB.NET脚本环境中,全局对象的成员函数可以直接调用,因此在vbsystem中定义一些例程就可以直接调用,可以在vbsystem中定义诸如Alert,ConFirm,Prompt,DebugPrint等成员函数,脚本中就能直接使用这些函数了。
访问数据库
由于应用需要,本文本编辑器要直接访问数据库,但该文本编辑器既使用于C/S程序又使用于B/S程序,当处于B/S构架时是不好直接连接数据库的,必须通过服务器程序来访问数据库。为了编程方便,应该抹杀掉这两种模式之间的差别。
大家考察一下.NET框架中操作数据库的类型,可以发现无论是专门操作SQLServer的在System.Data.SqlClient名称空间下面的那套对象还是操作OLEDB的在System.Data.OleDb空间下面的那套对象(其他类似有专门操作ODBC和ORACLE),这些套对象间最大的共同点就是都遵循一套在名称空间System.Data下接口。这些接口包括IDataReader , IDbCommand,IDbConnection,IDbDataParameter, IDataParameterColleciton等等 。若我们编了一套对象也实现了这些接口,那就相当于自定义了一套.NET数据库驱动程序。于是小弟很快根据B/S构架特性写了套对象,该套对象通过HTTP协议和WEB服务器交流数据,这套对象将SQL语句及其参数简单打包使用POST方法发送到指定的服务器页面后等待返回,服务器页面解析出SQL语句和参数查询数据库,将查询所得结果经过一定的编码返回为客户端,而客户端根据HTTP返回结果进行一番处理后就可以使用一个实现IDataReader的对象来访问了。这样在应用程序的其他模块若查询数据库则只要坚持使用System.Data.IDbConnection 等接口就可以了,如此就抹杀了C/S和B/S环境下访问数据库的差别了。
这种模式也算是一种WebService了,服务器页面可以使用任何类型,可以使用ASP,ASP.NET,PHP,J2E或JSP等等,只要能解析出SQL语句并返回特定结构的数据就行了。小弟的服务器为J2E,偶JAVA不熟,勉强用JSP实现了一个。我管这种模式叫两层半,实践证明这套还是管用的。
派生对象
定义了基础对象后就开始派生对象了,首先定义字符对象类型TextChar,一个文档内容中最主要的还是字符数据,在此为了实现方便,文档中每一个字符都是一个字符对象,字符对象重载了RefreshSize对象RefreshSize方法,用于根据当前绘制用的绘图对象(System.Drawing.Graph对象)的MeasureString来计算文字大小。注意默认情况下,该方法计算的字符串显示宽度后回额外的附加一些空白,为了计算实际的大小则使用System.Drawing.StringFormat.GenericTypographic参数。此外还有一个比较特殊的字符-制表符。这个字符的宽度是不固定的,需要在进行排版的时候才计算。
字符对象(TextChar)还派生RefreshView方法,该方法比较简单,根据Left,Top值进行坐标转换后算出绘制地点,然后调用System.Drawing.Graph.DrawString方法即可。字符对象还定义了自己的成员,比如Char属性返回对象表示的字符数据,Font表示绘制对象使用的字体,ForeColor表示绘制文本的颜色。
字符中的制表符比较特殊,因为它的宽度是不定的,而是根据它在文档视图中的位置而定的,因此在TextChar上在派生TextCharTab来转变处理这种情况,它新增了RefreshTabWidth方法,来根据对象在视图区域中的左端位置计算字符宽度。在此处我认定一个制表符步长等于四个下画线字符的宽度,制表符的右端坐标必须是制表符步长的自然数倍,因此根据制表符的位置来进行取模操作和其他操作就可以计算制表符的宽度。
为了表示段落而定义了段落对象TextParagraph,该对象不是容器对象,保存了段落对齐方式的信息,该元素的显示样式类似于Word中的段落符(硬回车)的样式。
还定义了行结束对象TextLineEnd,该对象模拟了Word的分行符(软回车)。
可以定义图片对象,经过对Word处理文档的行为观察,可以发现在Word文档中插入的图片和OLE对象特性很相似,因此为了考虑文本编辑器的可扩展性,首先在TextElement的基础派生出TextObject抽象类,该抽象类表示一个在文档中的对象,该对象由其派生的类决定。
在TextObject对象派生出TextImage表示一个图片对象,该对象重写了RefreshView方法,用于在绘图输出对象上绘制一个图片。还重载了FromXML和ToXML方法来和XML节点交换数据,可以设计将图片二进制数据以Base64格式保存为XML节点下。
此外还可以根据应用的需要从TextObject对象上派生其他的类型,比如直接读取数据库在界面上绘制曲线图等等,此时文档中的该对象可以动态的展示系统中最新的数据。
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者