### XML 在.net 平台下的自定义控件的应用

Xml 全称可扩展标记语言（extensible marked language）,这套语言系统由于在数据处理，跨平台等方面的独特优势，在近几年风靡全球。Xml 语言系统把任何数据都作为“键”和“值”来进行处理，这一点类似于很多数据库管理系统（DBMS），而且它与具体的机器指令无关，其存储方式是纯文本文件，因此具有出色的跨平台性。另外它允许用户创建自己的数据指令系统，在这套指令系统的框架下，用户可以把所有信息转换成易于存取的数据，大大加快了开发的周期和代码的可移植性。
既然 XML 这么好，那它到底是什么样子的呢？最近笔者因为课题的需要，开发了一个基于.net 平台下的 menu 控件，并且加入了 xml 特性。制作的步骤如下：
第一步：制作一个.net 平台下的 menu 控件
.net 平台下面的自定义控件的工作原理如下：控件对应于一个类（class），控件的所有属性通过类的成员变量来暴露，而控件的方法对应于 class 的成员函数。在控件被加载的手，系统会调用 class 的 render 方法，制作控件的时候，应该重载（override）这个 render 方法，使得在控件被加载的那 一刻，控件可以自己“绘制”自己，一般来说，在 render 方法里面要将关于控件界面绘制的那些 javascript 文件放入到输出流中。
由于这里重要是讲解后面 XML 的应用，所以这里只是把自定义控件的原来简要说明一下，下面罗列出相关对象，属性，方法。
整个 menu 控件分为 Topmenu，Submenu,Childrenmenu,MenuItem 四个对象,其相应的信息为：
控件属性：
ID:标识控件名字
MenubarHeight：菜单拦的高度
MenubarWidth:：菜单拦的宽度
BorderWidth::边框宽
AutoDropdown：true 表示自动下拉，false 表是单击鼠标下拉
DropdownDelay:下拉时间
Menufont:字体
LocationX:菜单的 x 位置
LocationY:菜单的 y 位置
XmlFile：xml 文件
XmlStream：xml 流
topmenu 对象属性：
ID：同上
Text：顶层菜单的文本
Isparent:true 表示有下一级菜单，否则为 false（false 默认）
Islink：需要用事件处理用 true，否则 false（false 默认）；
Bgcolor:背景色
Forecolor:前景色
HoveredBackcolor:鼠标放在上面的颜色
Topmenufont:字体
Linkurl:当 isparent 为 false 才有效，表示连接的 url
Borderwidth:topmenu 的边框宽
Itemheight:下一级菜单的高度（必须 isparent 为 true 才有效）
Itemwidth: 下一级菜单的宽度（必须 isparent 为 true 才有效）
Submenus:含有下一级菜单的数组列表
Submenu,Childrenmenu 和 MenuItem 的所有属性跟上面 Topmenu 一样，这里就不赘述了。
第二步，就是加入 XML 特性
注意，任何 xml 文档在其被处理之前最好先进行有效性验证，提供验证一般有两种重要的途径。其一就是提供 DTD（文档类型定义），实际上就是让用户提供指令集，然后在 xml 文档加载的时候对其进行有效性分析，看是否有无效指令，简单说就是创建一个编译环境；另外一个就是提供一个所谓的 schema。.其作用跟 DTD 完全一样，只是在表现形式上好于 DTD，因为它本身也是一个 XML 文档。这里我采用了 schema 的形式，当然了，读者用兴趣也可以将其替换问相应的 DTD 版本。下面列出该 schema 的关于控件和 topmenu 对象的代码，如果要看该文档的详细代码，请看 “代码.doc”。
menu.xdr：
＜?xml version="1.0" encoding="UTF-8"?＞
＜Schema name="menus" xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes"＞
＜description＞
menus schema used to validate menu.xml
＜/description＞
＜ElementType name="menu" model="closed" content="empty"＞
＜AttributeType name="id" dt:type="string" required="yes"/＞
＜atttibute type="id"/＞
＜element name="topmenu" model="closed" minOccurs="0" maxOccurs="*" content="empty"/＞
＜/ElementType＞
＜ElementType name="topmenu" model="closed" content="empty"＞
＜AttributeType name="id" dt:type="string" required="yes"/＞
＜AttributeType name="text" dt:type="string" required="yes"/＞
＜AttributeType name="linkurl" dt:type="string" required="yes"/＞
＜AttributeType name="isparent" dt:type="string" required="yes"/＞
＜atttibute type="id"/＞
＜atttibute type="text"/＞
＜atttibute type="linkurl"/＞
＜atttibute type="isparent"/＞
＜element name="submenu" model="closed" minOccurs="0" maxOccurs="*" content="empty"/＞
＜/ElementType＞
＜ElementType name="submenu" model="closed" content="empty"＞
＜AttributeType name="id" dt:type="string" required="yes"/＞
＜AttributeType name="text" dt:type="string" required="yes"/＞
＜AttributeType name="linkurl" dt:type="string" required="yes"/＞
＜AttributeType name="isparent" dt:type="string" required="yes"/＞
＜atttibute type="id"/＞
＜atttibute type="text"/＞
＜atttibute type="linkurl"/＞
＜atttibute type="isparent"/＞
＜element name="childrenmenu" model="closed" minOccurs="0" maxOccurs="*" content="empty"/＞
＜/ElementType＞
＜ElementType name="childrenmenu" model="closed" content="empty"＞
＜AttributeType name="id" dt:type="string" required="yes"/＞
＜AttributeType name="text" dt:type="string" required="yes"/＞
＜AttributeType name="linkurl" dt:type="string" required="yes"/＞
＜AttributeType name="isparent" dt:type="string" required="yes"/＞
＜atttibute type="id"/＞
＜atttibute type="text"/＞
＜atttibute type="linkurl"/＞
＜atttibute type="isparent"/＞
＜element name="menuitem" model="closed" minOccurs="0" maxOccurs="*" content="empty"/＞
＜/ElementType＞
＜ElementType name="menuitem" model="closed" content="empty"＞
＜AttributeType name="id" dt:type="string" required="yes"/＞
＜AttributeType name="text" dt:type="string" required="yes"/＞
＜atttibute type="id"/＞
＜atttibute type="text"/＞
＜/ElementType＞
＜/Schema＞
如果您对 html 比较熟悉的话，相信上面的代码即使是以前没有接触过也应该清楚了，在.xdr 中，有两个对象，其一是元素，用前缀 ElementType 来定义，另外一个是该元素所对应的属性，用前缀 atttibuteTpye，定义完这两个对象后，就是要将它们实例化，对应的前缀分别是 Element 和 atttibute，然后您就可以使用这两种已经实例化了的对象，就象使用 html 中＜a＞,＜l＞,＜body＞,＜head＞等标记一样。
为了更加清晰的说明上面的代码，我们这里举一个例子，相信读者一目了然：
＜menus xmlns='x-schema:Menu.xdr'＞
＜menu id='menuBar1'＞
＜topmenu id="xjtu" text="xjtu" isparent="true" linkurl="xjtu"＞＜/topmenu＞
＜submenu id="sina" text="sina" isparent="false" linkurl="sina"＞＜/submenu＞
＜topmenu id="sohu" text="sohu" isparent="false" linkurl="sohu"＞＜/topmenu＞
＜/menu＞＜/menus＞
创建完 xml 文档后，就要在程序里面读取 xml 文档，这里如果采用微软的 vs.net 平台开发的话，建议可以使用 XmlTextReader 来读取相关信息，具体细节可以查阅 MSDN。
第三步：使用控件
创建完了 menu 控件，现在就是在.net 平台下面来使用它。首先要在 vs.net 平台下面编译该控件，如果编译成功就可以使用它了。使用.net 自定义控件和使用一般的 ActiveX 控件很相似，启动 vs.net 平台下面的部件箱（可以直接在 ToolBar 上右击鼠标来得到），注意我们制作是不是基于 COM 组件，而是 ASP.net 组件，所以从这点上它与 COM 组件有本质的不同，通过 Browse 按钮可以选择该控件对应的 dll 文件，将其添加进你的工程。下面你还要在你的程序代码中加入下面的代码（其他代码略）
using 你的名字空间 ； （A）
还应该在 behind code 加入该控件的声明 (B)
事实上，无论是 A 处的代码还是 B 处的说明，都可以由 VS.NET 平台自动生成，如果使用其他平台并且不支持这种代码的自动添加的话，就可以手动添加。添加完之后，这样就可以和其他控件来进行使用了。而且在控件类代码中的所有的公有的成员变量，函数分别对应于控件的属性和方法。
这里需要指明的就是控件必须提供两个属性，那就是 XmlStream 和 XmlFile，如果用户已经制作好了控件的 XML 文件（该文件描述了控件的数据），或者是已经写好了一个 xml 代码的话，可以把代码和文件分别传给 XmlStream 和 XmlFile，后台程序（就是 dll 文件）通过调用一些 XML 的阅读器比如 XmlTextReader 来读取 xml 数据，这样就达到了控件支持 xml 属性了，进而也增强了控件的移植性和通用性。
本文主要讨论了 xml 在.net 平台下控件制作方面的应用，从上面的例子可以看出，xml 在数据的整合，处理方面确实有它独特的优势，如果你的项目中涉及到数据处理和跨平台的问题，可以考虑应用 XML.。