-
c#发现之旅—高情能ASP.net树状列表控件下
TreeNode 模板
TreeNode模板是XSLT模板文档的主要部分,其代码为
<!-- ******************* 输出一个树状列表节点 *************************** -->
<xsl:template name="TreeNode">
<!-- 定义一个 Level 参数,表示节点层次,默认 0 -->
<xsl:param name="Level">0</xsl:param>
<!-- 定义一个NodeID变量,表示当前节点的编号 -->
<xsl:variable name="NodeID">
<xsl:choose>
<xsl:when test="string-length(ID) > 0">
<xsl:value-of select="ID" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="generate-id( . ) " />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- 定义一个showChildNodes变量,表示当前节点是否默认显示子节点 -->
<xsl:variable name="ShowChildNode">
<xsl:if test="$Level < 1 ">1</xsl:if>
</xsl:variable>
<!-- 获得所有子节点的个数 -->
<xsl:variable name="ChildCount">
<xsl:value-of select="count(Nodes/Node) " />
</xsl:variable>
<!-- 判断是否存在子节点 -->
<xsl:variable name="HasChild">
<xsl:if test="$ChildCount > 0 or string-length( XMLSource ) > 0 ">1</xsl:if>
</xsl:variable>
<tr>
<td valign="top" align="left" width="16" height="16">
<!-- 显示前面的树状结构线 -->
<xsl:choose>
<xsl:when test=" $HasChild = '1' ">
<xsl:if test="position()!=last()">
<xsl:attribute name="background">SkyTreeViewControl_line.gif</xsl:attribute>
</xsl:if>
<img>
<xsl:attribute name="id">
<xsl:value-of select="concat($NodeID,'_expend')" />
</xsl:attribute>
<xsl:choose>
<xsl:when test="$ShowChildNode != '1' and position() != last()">
<xsl:attribute name="src">SkyTreeViewControl_collapse.gif</xsl:attribute>
<xsl:attribute name="SrcBack">SkyTreeViewControl_expend.gif</xsl:attribute>
</xsl:when>
<xsl:when test="$ShowChildNode = '1' and position() != last()">
<xsl:attribute name="src">SkyTreeViewControl_expend.gif</xsl:attribute>
<xsl:attribute name="SrcBack">SkyTreeViewControl_collapse.gif</xsl:attribute>
</xsl:when>
<xsl:when test="$ShowChildNode != '1' and position() = last()">
<xsl:attribute name="src">SkyTreeViewControl_lastcollapse.gif</xsl:attribute>
<xsl:attribute name="SrcBack">SkyTreeViewControl_lastexpend.gif</xsl:attribute>
</xsl:when>
<xsl:when test="$ShowChildNode = '1' and position() = last()">
<xsl:attribute name="src">SkyTreeViewControl_lastexpend.gif</xsl:attribute>
<xsl:attribute name="SrcBack">SkyTreeViewControl_lastcollapse.gif</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:attribute name="onclick">
<xsl:text>SkyTreeViewContrlExpendNodeByID('</xsl:text>
<xsl:value-of select="$NodeID" />
<xsl:text>' , false );</xsl:text>
</xsl:attribute>
</img>
</xsl:when>
<xsl:otherwise>
<xsl:if test="position()!=last()">
<img src="SkyTreeViewControl_child.gif" />
</xsl:if>
<xsl:if test="position()=last()">
<img src="SkyTreeViewControl_lastchild.gif" />
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</td>
<td valign="top" nowrap="1">
<!-- 用于生成节点图标HTML代码 -->
<img align="absmiddle" width="16" height="16">
<xsl:attribute name="onclick">
<xsl:text>SkyTreeViewContrlExpendNodeByID('</xsl:text>
<xsl:value-of select="$NodeID" />
<xsl:text>' , true );</xsl:text>
</xsl:attribute>
<xsl:attribute name="id">
<xsl:value-of select="concat($NodeID,'_icon')" />
</xsl:attribute>
<xsl:choose>
<xsl:when test="string-length( Icon ) != 0">
<xsl:attribute name="SrcBack">
<xsl:value-of select="Icon" />
</xsl:attribute>
<xsl:attribute name="src">
<xsl:value-of select="Icon" />
</xsl:attribute>
</xsl:when>
<xsl:when test="$HasChild = '1' and $ShowChildNode = '1'">
<xsl:attribute name="SrcBack">SkyTreeViewControl_close.bmp</xsl:attribute>
<xsl:attribute name="src">SkyTreeViewControl_open.bmp</xsl:attribute>
</xsl:when>
<xsl:when test="$HasChild = '1' and $ShowChildNode != '1'">
<xsl:attribute name="SrcBack">SkyTreeViewControl_open.bmp</xsl:attribute>
<xsl:attribute name="src">SkyTreeViewControl_close.bmp</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="src">SkyTreeViewControl_default.bmp</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</img>
<!-- 生成节点的文本 -->
<a class="SkyTreeViewControl_TreeNode" valign="top">
<xsl:attribute name="id">
<xsl:value-of select="concat( $NodeID, '_text')" />
</xsl:attribute>
<xsl:attribute name="onclick">
<xsl:text>SkyTreeViewContrlExpendNodeByID('</xsl:text>
<xsl:value-of select="$NodeID" />
<xsl:text>' , true );</xsl:text>
<xsl:if test="OnClick !=''">
<xsl:value-of select="OnClick" />
</xsl:if>
</xsl:attribute>
<xsl:if test="Link != ''">
<xsl:attribute name="href">
<xsl:value-of select="Link" />
</xsl:attribute>
</xsl:if>
<xsl:if test="string-length(XMLSource) > 0 ">
<xsl:attribute name="XMLSource">
<xsl:value-of disable-output-escaping="yes" select="XMLSource" />
</xsl:attribute>
</xsl:if>
<xsl:value-of select="concat( ' ' ,Text)" />
</a>
<xsl:if test="$ChildCount > 0 ">
<!-- 若有子节点则显示子节点 -->
<table border="0" cellspacing="0" cellpadding="0">
<xsl:attribute name="id">
<xsl:value-of select="concat( $NodeID , '_table' ) " />
</xsl:attribute>
<xsl:if test="$ShowChildNode != '1'">
<xsl:attribute name="style">display:none</xsl:attribute>
</xsl:if>
<xsl:for-each select="Nodes/Node">
<!-- 递归调用TreeNode模板本身来生成下一级的节点的HTML代码 -->
<xsl:call-template name="TreeNode">
<xsl:with-param name="Level"> <!-- 传递节点层次参数 -->
<xsl:value-of select="$Level + 1" />
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</table>
</xsl:if>
<xsl:if test="string-length(XMLSource) > 0 ">
<!-- 若节点的XMLSource存在则预先生成好“正在加载”字样,但隐藏起来 -->
<span style='display:none' class='SkyTreeViewControl_TreeNode'>
<xsl:attribute name="id">
<xsl:value-of select="concat( $NodeID , '_Loading' ) " />
</xsl:attribute>
<br />
<xsl:text>正在加载</xsl:text>
</span>
</xsl:if>
</td>
</tr>
</xsl:template>
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发
在这个模板中首先接受了一个名为Level的参数,该参数表示生成的树状列表的层次序号。
此处定义了一个名为“NodeID”的XSLT变量,将作为树状列表节点在HTML文档中的编号。
这里使用了XSLT函数generate-id,该函数属于创建一个惟一的编号。对相同的XML节点调用generate-id函数会得到相同的结果,对不同的XML节点调用该函数一定会得到不同的编号。注意,这里的编号在同一个XML文档中是惟一的,但对多个XML文档则不一定了。若对两个XML 文档中的XML节点调用该函数是有可能得到相同的编号。因此当同一个页面上有多个WEB控件,或者WEB控件支持动态加载子节点时,整个页面会对多个 XML文档执行XSLT转换,从而导致多个节点对象可能使用一样的节点编号的情况。若多个节点的编号一样会导致树状列表工作异常。这就是为什么在本演示程序中的“TreeViewNode.aspx”中使用“System.Guid.NewGuid”来手动的设置节点编号的原因。因为“NewGuid”函数会创建一个全球惟一编号,多次调用“NewGuid”函数而创建相同的编号的可能性基本上不存在,这从而保证了同一个页面中所有树状列表的节点编号的惟一性。
此处定义了名为“ShowChildNode”的XSLT变量。这里判断了Level参数值是否小于1,若小于1则参数值为1,表示初始化时该节点的子节点就显示出来。在这里可以控制树状列表初始化时显示多少层节点。
此处定义了“ChildCount”变量,用于存放子节点的个数,以后需要获得子节点个数时就用这个变量,避免重复计算。
此处定义了“HasChild”变量,用于判断是否有子节点,以后需要判断是否有子节点时就不需要重新计算了。
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发
准备工作完毕后开始输出HTML代码了。首先输出一个表格行,然后输出第一个单元格。
若节点存在子节点,若节点不是父节点的最后一个子节点时设置单元格的背景图片,从而模拟显示树状列表的层次结构线。此外由于节点存在子节点,因此可以展开和收缩,因此还输出展开和收缩控制点,并对控制点图片添加“onclick”属性,该属性中调用了控件输出的第三段HTML代码中定义的名为 “SkyTreeViewContrlExpendNodeByID”的javascript函数。
若节点不存在子节点则输出图片来模拟树状结构叶子节点连接线。
接下来就是输出第二个单元格了。首先输出节点前面的图标,若树状节点定义了Icon数据,则设置图标的SrcBack和src属性值为Icon数据。若没有指定Icon数据,则使用默认值。并设置显示图标的图片的“onclick”属性,这个“onclick”属性将会调用javascript函数“SkyTreeViewContrlExpendNodeByID”。
然后输出节点文本,输出超链接和OnClick属性值,若节点还有XMLSource值,这设置该值到HTML元素的XMLSource属性中。
系统判断XSLT变量“ChildCount”的值,若该节点存在子节点,则创建一个table元素,然后遍历所有的子节点,递归调用TreeNode模板,并传递Level参数,并使得Level参数值每次递归调用都增加1。
若节点的XMLSource值有效,还输出一个隐藏的提示“正在加载”的文本标签。
经过上述过程,一种高性能的可动态加载子列表的ASP.NET树状列表控件开发完毕,接着笔者将这个WEB控件投入使用。
Default.aspx
演示程序中有一个Default.aspx页面,为默认页面,这个页面就演示使用树状列表WEB控件,读者可以使用IE浏览器运行这个页面,可以看到两个树状列表,都是使用了3层节点来显示数据库中的客户订单信息。
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发
左边的列表内容是一下子加载了数据库中的所有的数据,页面加载后该树状列表已经包含了3072个节点。用户鼠标操作可以展开和收缩节点,可以点击货物节点来弹出一个消息框。
而右边的列表内容是动态加载的,页面加载后该列表只加载了客户信息,并没有加载定单信息和货物信息。当用户鼠标展开节点时,页面会根据需要自动的从后台加载相关的信息并动态的生成子节点。动态加载子节点能加快树状列表的初始化加载速度。
使用VS.NET 2005打开演示程序,重新编译一下,然后打开演示页面Default.aspx 的设计界面。其设计界面如下图
图片看不清楚?请点击这里查看原图(大图)。
可以看到页面上已经放置了两个树状列表控件。控件名为myTreeView和myTreeView2,鼠标点击某个树状列表控件,可以在旁边的属性窗口中列出了该控件的一些属性,其界面如下图所示,
树状列表控件比较重要的属性有
AutoScroll 是否自动显示滚动条。
DynamicLoadChild表示是否使用动态加载子节点。
GenerateAtServer 是否在服务器端生成HTML代码。
IndentXML 生成的XML是否进行缩进。
SelectedNodeStyleString 选中的节点的CSS样式字符串。
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发
TreeNodeStyleString 节点的CSS样式字符串。
查看该页面的HTML代码,可以看到这里使用了标签“SkyWebControl:SkyTreeViewControl”来定义一个树状列表控件。一些控件的属性值保存在HTML标签的属性中。
一般的。NET框架中的WEB控件在HTML代码中的前缀是“asp”,比如 “asp:label”,“asp:button”,“asp:TextBox”等。开发人员在开发自己的WEB控件也可以使用自己的HTMJL标签前缀,在树状列表控件的C#源代码中开头有一条指令
[assembly:System.Web.UI.TagPrefix("CS_Discovery" , "SkyWebControl")]
这条指令就指明自定义控件采用什么样的标签前缀。
查看这个页面的C#代码,可以看到代码还是不复杂的。主要包含了一个Page_Load函数,该函数的代码为
protected void Page_Load(object sender, System.EventArgs e)
{
if( myTreeView.Nodes.Count == 0 )
{
// 连接数据库
using( OleDbConnection conn = new OleDbConnection())
{
conn.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
+ this.Server.MapPath("SkyDemo.mdb");
conn.Open();
using( OleDbCommand cmd = conn.CreateCommand())
{
// 查询数据库,获得所有的客户名称、订单号和产品名称,
// 向树状列表myTreeView 填充内容
cmd.CommandText = @"
select
trim(Customers.CompanyName) ,
trim(orders.orderid & chr(32) & orders.shipname) ,
trim(products.productname)
from
customers ,
orders ,
orderdetails ,
products
where
customers.customerid = orders.customerid
and orders.orderid = orderdetails.orderid
and orderdetails.productid = products.productid
order by
trim(Customers.CompanyName) ,
orders.orderid,
trim(products.productname)";
OleDbDataReader reader = cmd.ExecuteReader();
// 客户公司节点
SkyTreeNode CompanyNode = null;
// 客户订单节点
SkyTreeNode OrderNode = null;
while( reader.Read())
{
// 读取客户公司名称
string cname = Convert.ToString( reader.GetValue( 0 ));
// 读取订单编号和订货人名称
string oname = Convert.ToString( reader.GetValue( 1 ));
// 读取产品名称
string pname = Convert.ToString( reader.GetValue( 2 ));
if( CompanyNode == null || cname != CompanyNode.Text )
{
// 创建新的客户公司节点并添加到控件myTreeView 中
OrderNode = null;
CompanyNode = new SkyTreeNode();
CompanyNode.Text = cname ;
CompanyNode.Icon = "customer.bmp";
myTreeView.Nodes.Add( CompanyNode );
}
if( OrderNode == null || oname != OrderNode.Text )
{
// 创建新的订单节点并添加到客户公司节点下
OrderNode = new SkyTreeNode();
OrderNode.Text = oname ;
OrderNode.Icon = "order.bmp";
CompanyNode.Nodes.Add( OrderNode );
}
// 创建新的货物节点并添加到订单节点下
SkyTreeNode ProductNode = new SkyTreeNode();
ProductNode.Text = pname ;
ProductNode.Icon = "product.bmp";
ProductNode.OnClick = "alert('" + pname + "')" ;
OrderNode.Nodes.Add( ProductNode );
}//while
reader.Close();// 树状列表myTreeView 填充完毕
// 查询数据库获得所有的客户编号和客户名称,准备填充树状列表控件myTreeView2
cmd.CommandText = "Select customerid , companyname from customers "
+" order by companyname";
reader = cmd.ExecuteReader();
while( reader.Read())
{
// 创建新的客户节点并添加到控件myTreeView2 下。
string NodeID = System.Guid.NewGuid().ToString();
SkyTreeNode node = new SkyTreeNode();
node.ID = NodeID ;
node.Text = Convert.ToString( reader.GetValue( 1 ));
node.Icon = "customer.bmp";
// 设置节点的XMLSource属性准备客户端动态加载子节点
// 此处需要配合使用TreeViewNodeXml.aspx 页面。
node.XMLSource = "TreeViewNodeXml.aspx?KeyType=customerid&KeyValue="
+ Convert.ToString( reader.GetValue( 0 ) ) ;
myTreeView2.Nodes.Add( node );
}
reader.Close();
}//using
}//using
}
this.lblInfo.Text = "本控件共有节点" + myTreeView.AllNodes.Count + " 个";
this.lblInfo2.Text = "本控件初始化有" + myTreeView2.AllNodes.Count
+ " 个节点,能动态加载子节点";
}
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发
在这个函数中,首先连接程序目录下的演示数据库 SkyDemo.mdb,然后执行一个比较复杂的SQL查询,获得数据库中所有的客户名称,订单信息和订单货物信息,然后填充到myTreeView的Nodes属性中,从而在内存中构造了一个三层的树状结构。
这里面可以看到树状列表没有自动的数据源绑定功能。由于树状结构处理过程复杂,简单的数据源绑定难于实现,因此这个树状列表控件不提供数据源绑定功能,而是需要使用者编程向列表添加节点。
填充第一个树状列表后,程序然后再次查询数据库,获得所有的客户名称和编号,然后填充到myTreeView2 的Nodes中,并设置每个节点的XMLSource属性。而XMLSource属性就规定了客户端动态加载子节点使用的XML文档的URL地址。这里使用了另外一个页面“TreeViewNodeXml.aspx”作为XML文档的提供者,并向该页面传递参数来决定生成什么样的节点定义XML文档。而且该页面生成的XML文档格式符合刚才设计的节点XML文档格式。
在这个页面中,没有任何生成HTML代码的代码,所做的只是向页面拖拽放置树状列表,然后查询数据库填充控件的节点结构,可以说使用比较方便,这个树状列表控件内部自动完成了所有的底层工作。
TreeViewNodeXml.aspx
本页面是一个后台服务页面,用于向第二个树状列表动态的提供子节点信息。该页面也不复杂,它没有HTML代码,其ASPX文件只有一行代码,其代码如下
<%@ Page language="c#" Inherits="CS_Discovery.TreeViewNodeXml" CodeFile="TreeViewNodeXml.aspx.cs" %>
查看该页面的C#代码,只有一个Page_Load函数,其代码为
protected void Page_Load(object sender, System.EventArgs e)
{
// 关键字的类型
string KeyType = this.Request.QueryString["KeyType"] ;
// 关键字的数值
string KeyValue = this.Request.QueryString["KeyValue"];
// 设置页面输出格式
this.Response.ContentEncoding = System.Text.Encoding.GetEncoding( 936 );
this.Response.ContentType = "text/xml";
// 根据页面输出流创建XML文档书写器
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter( this.Response.Output );
// 设置带缩进
writer.IndentChar = ' ' ;
writer.Indentation = 3;
writer.Formatting = System.Xml.Formatting.Indented ;
// 开始输出XML文档
writer.WriteStartDocument();
writer.WriteStartElement("Nodes");
// 连接数据库
using( System.Data.OleDb.OleDbConnection conn = new System.Data.OleDb.OleDbConnection())
{
conn.ConnectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
+ this.Server.MapPath("SkyDemo.mdb");
conn.Open();
// 查询数据库
using( System.Data.OleDb.OleDbCommand cmd = conn.CreateCommand())
{
if (KeyType == "customerid")
{
// 关键字为客户编号,则此时查询该客户编号下的所有的订单信息
cmd.CommandText = "select orderid , shipname from orders where customerid='"
+ KeyValue +"' order by orderid";
System.Data.IDataReader reader = cmd.ExecuteReader();
while( reader.Read())
{
writer.WriteStartElement("Node");
string NodeID = System.Guid.NewGuid().ToString();
// 创建节点编号
writer.WriteElementString("ID" , NodeID );
writer.WriteElementString("Icon","order.bmp");
// 节点文本就是订单编号和订单人姓名
writer.WriteElementString("Text" ,
Convert.ToString( reader.GetValue( 0 ) )
+ "-" + Convert.ToString( reader.GetValue( 1 )));
// 输出生成子节点使用的XML文档URL地址,从功能上看相当于递归调用本页面
writer.WriteElementString("XMLSource" ,
"TreeViewNodeXml.aspx?KeyType=orderdetails&KeyValue="
+ Convert.ToString( reader.GetValue( 0 )) );
writer.WriteEndElement();
}
reader.Close();
}
else if( KeyType == "orderdetails" )
{
// 关键字为订单编号,则此时查询该订单编号下的所有的货物的信息
cmd.CommandText = @"
Select
products.productname ,
orderdetails.quantity
from
orderdetails ,
products
where
orderdetails.productid = products.productid
and orderdetails.orderid=" + KeyValue + " order by productname ";
System.Data.IDataReader reader = cmd.ExecuteReader();
while( reader.Read())
{
writer.WriteStartElement("Node");
string NodeID = System.Guid.NewGuid().ToString();
writer.WriteElementString("ID" , NodeID );
writer.WriteElementString("Icon" , "product.bmp" );
writer.WriteElementString("Text" ,
Convert.ToString( reader.GetValue( 0 )));
writer.WriteElementString("OnClick" ,
"alert('" + Convert.ToString( reader.GetValue( 0 )) + "')" );
writer.WriteEndElement();
}
reader.Close();
}
}//using
}//using
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Close();
}
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发
这段代码过程也不复杂,首先获得名为KeyType和KeyValue的页面参数。然后在页面输出流上创建一个XML文档书写器,然后连接数据库准备查询数据。
若参数KeyType的值等于“customerid”,则表示KeyValue为一个客户编号,此时页面是要求输出输出该编号客户名下的所有的订单信息,此时代码连接数据库查询查询Orders数据表,对每一个查询记录输出一个名为Node的XML元素,使用Guid.NewGuid()创建一个不重复的节点编号,输出节点图标,文本信息。此外还输出XMLSource信息。这里的XMLSource信息表示订单节点的子节点信息来源,也就是指定订单的货品信息XML文档地址,这里还是指向页面TreeViewNodeXml.aspx,使用的KeyType参数值为orderdetails,而 KeyValue 参数值就是订单编号。
若页面参数KeyType的值等于orderdetails,则KeyValue为一个订单编号,此时页面被要求输指定编号的订单中的详细货物清单,此时程序执行一个简单的联合查询,获得指定订单编号的所有货品信息,然后输出XML文档。由于货品信息没有子节点,因此也就不输出XMLSource 元素了。
其他文件
这个树状列表控件还包含了一些其他文件,比如SkyTreeViewControl.bmp是控件在VS.NET窗体设计器工具箱上显示的小图标。而其他的以 SkyTreeViewControl_开头的图片文件用于模拟显示树状列表的层次结构,还有一些默认图标文件。
其他说明
读者可以试着运行演示页面Default.aspx,可以发现对树状控件进行不同的设置,生成的HTML页面大小是不相同的。比如笔者设置左边的列表的GenerateAtServer属性为false,IndentXML为false时,也就是启动客户端生成HTML代码,则生成的客户端加载的 HTML页面大小为三百多K,查看其HTML源代码,发现树状列表的节点XML文档占据着HTML文档的大部分。若笔者设置左边的列表的 GenerateAtServer属性为true,也就是在服务器端生成HTML代码,则客户端显示的HTML页面大小接近2兆。体积瞬间增长到6倍,也就是说当树状列表节点比较多时(这里有三千多个),则在服务器端生成代码和在客户端生成代码这两种模式存在很大的差别。这是因为当在客户端生成代码时,服务器端向客户端发送的是XML文档,只包含比较纯粹的数据,体积小;而在服务器端生成代码时,服务器端发送的是HTML代码,除了包含数据外,还有大量的用于控制界面样式的HTML代码,这导致HTML代码量大。
在以前的XML/XSLT章节中,笔者提过,在WEB开发中采用XML/XSLT技术能比较大的改善WEB程序的网络传输性能,在这里用于显示大量节点的树状列表的应用就是一个范例。
部署控件
这个树状列表控件开发完毕后包含在一个DLL文件中,编译程序前要注意设置文件“SkyTreeViewControl.bmp”和“SkyTreeViewControl.xslt”的“生成操作”属性值为“嵌入的资源”。
开发人员在开发其他系统时可以添加这个DLL的引用,在VS.NET的窗体设计器的工具箱上可以看到这个树状列表的图标,若没有则在工具箱上右击显示快捷菜单,选中“添加/移除项目”,在对话框中选择浏览,显示包含控件的DLL 文件,然后选择SkyTreeViewControl即可。
开发人员从工具箱中拖拽一个树状列表控件到ASP.NET页面上就可以开始使用了。
在开发和部署包含树状列表的WEB 程序前,需要将所有“SkyTreeViewControl_”前缀的图片文件拷贝到程序第一级目录下。
小结
在本章中,大家一起研究了目前一些ASP.NET项目中使用的树状列表的原理和出现的问题,并开发新的树状列表控件。这种WEB树状列表控件支持在客户端和服务器端使用XSLT技术生成HTML代码,并能在客户端动态加载子列表,相对于旧控件,新控件加载速度快,能显示大量的节点。
此外读者还学习了IE浏览器所特有的XML数据岛的功能,并使用javascript脚本在客户端执行XSLT转换。这里读者可以看到XSLT技术作为国际标准技术已经得到广泛的支持。
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发
在这个模板中首先接受了一个名为Level的参数,该参数表示生成的树状列表的层次序号。
此处定义了一个名为“NodeID”的XSLT变量,将作为树状列表节点在HTML文档中的编号。
这里使用了XSLT函数generate-id,该函数属于创建一个惟一的编号。对相同的XML节点调用generate-id函数会得到相同的结果,对不同的XML节点调用该函数一定会得到不同的编号。注意,这里的编号在同一个XML文档中是惟一的,但对多个XML文档则不一定了。若对两个XML 文档中的XML节点调用该函数是有可能得到相同的编号。因此当同一个页面上有多个WEB控件,或者WEB控件支持动态加载子节点时,整个页面会对多个 XML文档执行XSLT转换,从而导致多个节点对象可能使用一样的节点编号的情况。若多个节点的编号一样会导致树状列表工作异常。这就是为什么在本演示程序中的“TreeViewNode.aspx”中使用“System.Guid.NewGuid”来手动的设置节点编号的原因。因为“NewGuid”函数会创建一个全球惟一编号,多次调用“NewGuid”函数而创建相同的编号的可能性基本上不存在,这从而保证了同一个页面中所有树状列表的节点编号的惟一性。
此处定义了名为“ShowChildNode”的XSLT变量。这里判断了Level参数值是否小于1,若小于1则参数值为1,表示初始化时该节点的子节点就显示出来。在这里可以控制树状列表初始化时显示多少层节点。
此处定义了“ChildCount”变量,用于存放子节点的个数,以后需要获得子节点个数时就用这个变量,避免重复计算。
此处定义了“HasChild”变量,用于判断是否有子节点,以后需要判断是否有子节点时就不需要重新计算了。
编缉推荐阅读以下文章
- C#发现之旅 - 高性能ASP.NET树状列表控件(中)
- C#发现之旅 - 高性能ASP.NET树状列表控件(上)
- C#发现之旅:C#开发Windows Service程序(下)
- C#发现之旅:C#开发Windows Service程序(上)
- C#发现之旅之终结篇第十讲 文档对象模型
- C#发现之旅第九讲 ASP.NET验证码技术
- C#发现之旅第八讲 ASP.NET图形开发带超链接的饼图
- C#发现之旅第七讲 C#图形开发高级篇
- C#发现之旅第一讲 C#-XML开发
- C#发现之旅第二讲 C#-XSLT开发