程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> C#發現之旅-高性能ASP.NET樹狀列表控件(下)

C#發現之旅-高性能ASP.NET樹狀列表控件(下)

編輯:關於C#

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 &lt; 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>

在這個模板中首先接受了一個名為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”變量,用於判斷是否有子節點,以後需要判斷是否有子節點時就不需要重新計算了。

准備工作完畢後開始輸出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層節點來顯示數據庫中的客戶訂單信息。

左邊的列表內容是一下子加載了數據庫中的所有的數據,頁面加載後該樹狀列表已經包含了3072個節點。用戶鼠標操作可以展開和收縮節點,可以點擊貨物節點來彈出一個消息框。

而右邊的列表內容是動態加載的,頁面加載後該列表只加載了客戶信息,並沒有加載定單信息和貨物信息。當用戶鼠標展開節點時,頁面會根據需要自動的從後台加載相關的信息並動態的生成子節點。動態加載子節點能加快樹狀列表的初始化加載速度。

使用VS.NET 2005打開演示程序,重新編譯一下,然後打開演示頁面Default.aspx 的設計界面。其設計界面如下圖

可以看到頁面上已經放置了兩個樹狀列表控件。控件名為myTreeView和myTreeView2,鼠標點擊某個樹狀列表控件,可以在旁邊的屬性窗口中列出了該控件的一些屬性,其界面如下圖所示,

樹狀列表控件比較重要的屬性有

AutoScroll 是否自動顯示滾動條。

DynamicLoadChild表示是否使用動態加載子節點。

GenerateAtServer 是否在服務器端生成HTML代碼。

IndentXML 生成的XML是否進行縮進。

SelectedNodeStyleString 選中的節點的CSS樣式字符串。

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
        + " 個節點,能動態加載子節點";
}

在這個函數中,首先連接程序目錄下的演示數據庫 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();
}

這段代碼過程也不復雜,首先獲得名為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技術作為國際標准技術已經得到廣泛的支持。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved