1. 程式人生 > 實用技巧 >ASP。NET TreeView控制元件和客戶端的瀏覽器

ASP。NET TreeView控制元件和客戶端的瀏覽器

介紹

這篇文章演示瞭如何使用免費的來自微軟的c#和ASP的TreeView控制元件。NET以及如何攔截客戶端瀏覽器上的伺服器端事件,以減少回發次數,並通過處理客戶端上的主要事件來提高應用程式的效能。

在離開這篇文章之前,請提供一個評級/投票

這是唯一的方式,作者獲得任何型別的榮譽,他們的工作,他們自由地分享給每個人。看到那些幫助了超過10萬人的文章,而只有不到200人費心去投票或提供評級,這讓人很難過。

背景

在web開發中使用的一個常見控制元件是TreeView。開發者可以選擇使用DHTML,購買第三方控制元件或者使用微軟提供的免費TreeView在ASP.NET中使用。這篇文章主要討論如何利用微軟提供的免費TreeView控制元件。

使用微軟的自由控制元件的一個問題是缺乏支援,而且這個控制元件是設計來利用ASP。NET的伺服器端事件架構。有經驗的web開發人員努力減少或消除儘可能多的伺服器往返(通常稱為post-back),以提高終端使用者的滿意度和響應時間。

本文將演示如何使用微軟的TreeView控制元件來攔截客戶端上典型的伺服器端事件而不丟失功能。本文中的示例是基本的,演示瞭如何在客戶端獲取和使用的樹檢視的每個節點中儲存“元資料”。

本文中使用的控制元件是從Microsoft免費下載的,控制元件的概述包含在它們的線上文件中。

什麼是微軟的樹狀檢視?

樹檢視提供了一個面向物件的資料和元資料的分層或父/子關係檢視。樹檢視最常見的例子是Windows資源管理器的目錄結構,其中磁碟驅動器包含資料夾,資料夾包含子資料夾,資料夾包含檔案。

MS TreeView控制元件公開了幾個可用於動態構建樹的類。您將使用的兩個主要類是TreeView和TreeNode類。TreeView類提供了容納1 - N個樹狀節點的容器。樹節點表示父/子結構中的各個項。以下是兩個類的特點:

樹檢視/節點特徵TreeView控制元件是顯示父/子關係的容器。TreeView控制元件包含1 - N個樹節點。樹節點表示父/子關係中的元素。樹節點可以是其他樹節點的父節點和/或子節點。具有子節點的樹節點可以展開以顯示它們的子節點。具有子節點的樹節點可以摺疊以隱藏它們的子節點。樹節點有一個名為NodeData的屬性,可以用來儲存元資料。樹節點可以顯示影象(想想Windows資源管理器,其中顯示關閉或開啟的資料夾的影象)。樹節點可以是到其他web頁面或站點的超連結。

什麼是NodeData屬性?

TreeNode類提供了一個名為NodeData的屬性。這個屬性非常適合儲存您需要在客戶機或伺服器上訪問的元資料。

問題是屬性的基礎型別是字串。那麼如何在屬性中儲存幾個元資料片段呢?我發現最簡單的方法是建立一個分隔的鍵值對列表,這些鍵值對可以在客戶機或伺服器上訪問。我通常使用分號(;)作為主分隔符,並用等號(=)分隔鍵和值。例如,我將元資料儲存在一個樹節點的NodeData屬性中,如下:

隱藏,複製程式碼
TreeNode tn = new TreeNode();

tn.Text = "Root Parent Node";

tn.NodeData = "Id=1000;Name=Mike Elliott;Article=ASP.NET " + 
               "Tree View Control & the Client's Browser";

您可以通過訪問元素的NodeData屬性在客戶機上獲取NodeData屬性的資訊。這將允許您獲得關於使用者選擇的樹節點的詳細資訊,並根據需要顯示或提交資訊。這一功能可以減少大多數往返或後回操作,這些操作通常是由於需要與終端使用者選擇的節點關聯的元資料而引起的(本文稍後將對此進行演示)。

您可以選擇使用XML而不是鍵值對,但是出於效能原因,我更喜歡使用鍵值對,因為它們儲存在陣列中。

準備構建示例

在開始示例之前,我想提供一些設定資訊,以備您繼續學習。

第一步是下載微軟的免費控制套件。控制元件套件包含的不僅僅是TreeView;但是,我不打算在本文中介紹選項卡控制元件。從本文前面列出的URL下載後,您將必須構建或執行build.bat檔案來生成Microsoft.Web.UI。按照下載中獲得的自述檔案中的說明來組裝WebControls。

請做好準備,隨免費下載一起釋出的.bat檔案有一個bug,可能會阻止.dll的生成(大多數時候),並且沒有給出任何警告或異常訊息。

在記事本中開啟build.bat檔案,找到如下程式碼行:

隱藏,複製程式碼
csc.exe /out:build\Microsoft.Web.UI.WebControls.dll @IEWebControls.rsp

除非將css .exe編譯實用程式放在主路徑中,或者將可執行檔案的副本放在system或system32目錄中,否則.bat檔案將找不到編譯實用程式,並以靜默方式失敗。

要糾正這個問題,可以修改.bat檔案,使其具有csc.exe編譯工具的完整路徑,如下所示(位置和版本可能在您的機器上不同):

隱藏,複製程式碼
C:\Windows\Microsoft.NET\Framework\v1.14322\csc.exe 
    /out:build\Microsoft.Web.UI.WebControls.dll @IEWebControls.rsp

這將糾正構建問題,並允許按照下載檔案中的自述檔案生成microsoft . web . ui . webcontrol .dll。按照readme檔案中的詳細說明完成安裝說明。

正確安裝控制庫之後,建立一個新的ASP。並新增一個對新建立的Microsoft.Web.UI.WebControls.dll的引用。接下來,新增一個名為TVExample的Web表單。aspx到新的web專案。現在就可以按照本文的描述複製和貼上程式碼了。

客戶端事件

我將演示如何在客戶機上攔截以下事件,而不是允許伺服器端回發。

EventDescriptiononselectedindexchange當終端使用者單擊樹檢視中的節點時觸發的事件。當終端使用者展開節點時觸發的事件。oncollapse當終端使用者摺疊一個節點時觸發的事件。當終端使用者雙擊一個節點時觸發的事件。onContextMenu事件 當終端使用者右鍵單擊樹檢視中的節點時觸發的事件。 您必須禁止顯示典型的右鍵上下文選單,並將其替換為您的功能。

這些是您需要攔截的最常見事件,以防止發生伺服器端內部事件或post-back。這將極大地增加終端使用者的體驗,並增加響應時間。它還將通過將大量工作推到客戶機的機器上來減少web伺服器上的負載。

下面的示例將顯示截獲的事件,如何從樹節點的NodeData屬性(在客戶機上)獲取元資料,以及如何從NodeData屬性解析鍵值對資訊。

獲取密碼

在進入程式碼之前,我想說的一點是ASP。NET通過IAttributeAccessor介面提供對大多數HTML和JavaScript屬性的訪問。HtmlControl, ListItem, UserControl和WebControl型別包括這個介面的內在實現。此介面允許以程式設計方式訪問伺服器控制元件標記中定義的任何屬性。這是一個很好的特性,允許您通過將事件指向自己的JavaScript函式來攔截伺服器端事件,本文後面將介紹這一點。

HTML和JavaScript程式碼,我們將使用攔截什麼是典型的伺服器端事件是相當直接的,應該是自我記錄,但這裡有幾個高點,你應該注意:

  • 我們註冊了microsoft。web。ui。HTML頁面中的web控制元件。這為我們提供了建立樹檢視的宣告式訪問:複製Code@Register TagPrefix = " iewc " 名稱空間= " Microsoft.Web.UI.WebControls " 組裝= " Microsoft.Web.UI.WebControls "
  • 對於我們在客戶端攔截的每個事件,將呼叫一個JavaScript函式:Hide縮小,複製程式碼//擷取客戶端上的索引更改事件。 // TVIndexChanged()函式 { ChangeText('node changed'); } 擷取客戶端上的展開事件。 // TVNodeExpand()函式 { ChangeText(“onexpand”); } //在客戶端攔截崩潰事件。 // TVNodeCollapse()函式 { ChangeText(“oncollapse”); } 擷取客戶端上的雙擊事件。 // TVDoubleClick()函式 { ChangeText(“雙擊”); } 擷取客戶端上的右擊事件。所選的 樹節點被更改為終端使用者所在的節點 //右鍵單擊,可以獲得該節點的元資料。 // TVRightClick()函式 { //獲取樹檢視的控制代碼。 var tree = GetTreeHandle(); var treenode; if (null ==樹|| undefined ==樹) 返回; //獲取選定的樹節點。 treenode =樹。getTreeNode(事件。treeNodeIndex); if (null == treenode || undefined == treenode) 返回; //使右擊的樹節點成為 / /選中的節點。 樹。selectedNodeIndex = event.treeNodeIndex; ChangeText(“oncontextmenu事件”); }
  • 有一個JavaScript函式可以讓我們獲得TreeView控制元件本身的控制代碼:Hide複製程式碼//獲取TreeView的控制代碼。 // GetTreeHandle()函式 { var樹; var treeName = 'tvControl'; //獲得一個處理TreeView。 文件樹=。getElementById (treeName); if (null ==樹|| undefined ==樹) 返回null; 返回樹; }
  • 有一個JavaScript函式允許我們獲得終端使用者選擇的樹節點物件的控制代碼:Hide 複製程式碼//獲取TreeView所選節點的控制代碼。 // GetSelectedNode()函式 { var tree = GetTreeHandle(); var treeNode; if (null ==樹|| undefined ==樹) 返回null; treeNode =樹。getTreeNode(樹。selectedNodeIndex); if (null == treeNode || undefined == treeNode) 返回null; 返回treeNode; }
  • 有一個JavaScript函式用於檢索NodeData屬性的資訊並返回傳入的鍵的值。這是最重要的函式之一,它允許您檢索客戶端上的元資料,並在必要時使用它:Hide 縮小,Copy Code//從NodeData獲取searchKey的值 //樹木的。 // 函式GetKeyValue(searchKey) { //獲取選定樹節點的控制代碼。 var treenode = GetSelectedNode(); //驗證節點控制代碼。 if (null == treenode || undefined == treenode) 返回null; //獲取節點的NodeData屬性的值。 var nodeDataAry = treenode。getAttribute(“nodeData”); if (null == nodeDataAry || undefined == nodeDataAry) 返回null; nodeDataAry = nodeDataAry。分割(“;”); if (null == nodeDataAry || undefined == nodeDataAry || 0祝辭= nodeDataAry。長度) 返回null; var計算= 0; var returnValue = null; 當(計數;nodeDataAry。長度) { var workingItem = nodeDataAry[count]; if (0 >= workingItem)長度) { 數+ +; 繼續; } //將字串分割成鍵值對。 var kv = workingItem分割(' = '); 如果(1 >= kv)長度) { 數+ +; 繼續; } var key = kv[0]; var kValue = kv[1]; if (key != searchKey) { 數+ +; 繼續; } returnValue = kValue; 打破; } 返回returnValue; }

整個TVExample。aspx程式碼集

隱藏,縮小,複製程式碼
<%@ Page language="c#" Codebehind="TVExample.aspx.cs" 
    AutoEventWireup="false" 
    Inherits="Mike.Elliott.Articles.TreeView.TVExample" %>
<%@ Register TagPrefix="iewc" 
    Namespace="Microsoft.Web.UI.WebControls" 
    Assembly="Microsoft.Web.UI.WebControls" %>

  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 

  <html>
     <head>
       <title>Tree View Example</title>
       <meta name="GENERATOR" 
           Content="Microsoft Visual Studio .NET 7.1">
       <meta name="CODE_LANGUAGE" Content="C#">
       <meta name=vs_defaultClientScript content="JavaScript">
       <meta name=vs_targetSchema 
         content="http://schemas.microsoft.com/intellisense/ie5">
     </head>
   <body MS_POSITIONING="GridLayout">
   
   <script language="javascript">
   // Intercepts the index changed event on the client.
   //
   function TVIndexChanged()
   {
       ChangeText( 'node changed' );
   }
   
   // Intercepts the expand event on the client.
   //
   function TVNodeExpand()
   {
       ChangeText( 'onexpand' );
   }
   
   // Intercepts the collapse event on the client.
   //
   function TVNodeCollapse()
   {
       ChangeText( 'oncollapse' );
   }
   
   // Intercepts the double-click event on the client.
   //
   function TVDoubleClick()
   {
       ChangeText( 'dblclick' );
   }
   
   // Intercepts the right-click event 
   // on the client. The selected 
   // tree node is changed to the node 
   // over which the end user has 
   // right-clicked so that, that node's 
   // meta-data can be obtained.
   //
   function TVRightClick()
   {
       // Get a handle to the tree view. 
       var tree = GetTreeHandle();
       var treenode;
   
       if ( null == tree || undefined == tree )
           return;
   
       // Get the selected node.
       treenode = tree.getTreeNode( event.treeNodeIndex );  
   
       if ( null == treenode || undefined == treenode )
           return;
   
       // Cause the tree node that was 
       // right-clicked on to become the 
       // selected node.  
       tree.selectedNodeIndex = event.treeNodeIndex;   
      
       ChangeText( 'oncontextmenu' );
   }
        
   // Simply changes the information 
   // in the display text boxes to 
   // demonstrate how to obtain meta-data 
   // from the selected node's 
   // NodeData property on the client.
   //
   function ChangeText( eventName )
   {
       var treeNode = GetSelectedNode();
       
       if ( null == treeNode || undefined == treeNode )
       {
           return;
       }     
       
       var nodeData = 
          treeNode.getAttribute( 'nodeData' ).split( ';' );          
           
       var id = GetKeyValue( 'SomeId' );
       var name = GetKeyValue( 'Name' );
                            
       document.getElementById( 'txtEvent' ).value = 
                                            eventName;
       document.getElementById( 'txtId' ).value = id;
       document.getElementById( 'txtName' ).value = name;
   }
   
   // Gets the value of the searchKey 
   // from the NodeData of a TreeNode.
   //
   function GetKeyValue( searchKey )
   {   
       // Get a handle to the selected TreeNode.
       var treenode = GetSelectedNode();
     
       // Validate the node handle.
       if ( null == treenode || undefined == treenode )
           return null;
   
       // Get the node's NodeData property's value.
       var nodeDataAry = treenode.getAttribute( 'nodeData' );
   
       if ( null == nodeDataAry || undefined == nodeDataAry )
           return null;
    
       nodeDataAry = nodeDataAry.split( ';' );
   
       if ( null == nodeDataAry || undefined == nodeDataAry || 
         0 >= nodeDataAry.length )
           return null;
    
       var count = 0;
       var returnValue = null;
   
       while ( count < nodeDataAry.length )
       {
           var workingItem = nodeDataAry[ count ];
    
           if ( 0 >= workingItem.length )
           {
               count++;
               continue;
           }
     
           // Split the string into its key value pairs.
           var kv = workingItem.split( '=' );
   
           if ( 1 >= kv.length )
           {
               count++;
               continue;
           }
     
           var key = kv[ 0 ];
           var kValue = kv[ 1 ];
   
           if ( key != searchKey )
           {
               count++;
               continue;
           }
   
           returnValue = kValue;
           break;
       }       
    
       return returnValue;
   }
    
   // Gets a handle to the TreeView.
   //
   function GetTreeHandle()
   {
       var tree;
       var treeName = 'tvControl';
      
       // Get a handle to the TreeView.
       tree = document.getElementById( treeName );
   
       if ( null == tree || undefined == tree )
           return null;
   
       return tree;
   }     
   
   // Gets a handle to the TreeView's selected node.
   //
   function GetSelectedNode()
   {
       var tree = GetTreeHandle();
       var treeNode;
   
       if ( null == tree || undefined == tree )
           return null;
   
       treeNode = tree.getTreeNode( tree.selectedNodeIndex );  
    
       if ( null == treeNode || undefined == treeNode )
           return null;
   
       return treeNode;
   }   
   </script>
   
   <form id="frmTVExample" method="post" runat="server">
       <table width="100%" align="center" border="0">
           <tr><td>
             <iewc:treeview id="tvControl" runat="server" 
                 SystemImagesPath=
                       "/webctrl_client/1_0/treeimages/" 
                 EnableViewState="False">
             </iewc:treeview>
           </td></tr>
           <tr>
           <td><input type="text" id="txtId" name="txtId">
           </td></tr>
           <tr>
           <td><input type="text" id="txtName" name="txtName">
           </td></tr>
           <tr>
           <td><INPUT type="text" id="txtEvent" name="txtEvent">
           </td> </tr>
       </table>
   </form>
   
   </body>
   </html>

c或後面的程式碼(本節不包括OnInit和InitializeComponent方法NET為您建立,所以不要刪除這些方法或它們的內容。它也不包括所有的using指令,所以不要刪除為您建立的using指令,但是您應該新增using Microsoft.Web.UI。WebControls指令如例子中所示):

隱藏,縮小,複製程式碼
using Microsoft.Web.UI.WebControls;

namespace Mike.Elliott.Articles.TreeView
{
    public class TVExample : System.Web.UI.Page
    {
        protected Microsoft.Web.UI.WebControls.TreeView tvControl;

        private void Page_Load( object sender, System.EventArgs e )
        {
            // Create the root tree node.
            TreeNode root = new TreeNode();
            root.Text = "Root Parent Node";
            root.NodeData = "SomeId=1000;Name=Mike Elliott";

            // Create a child node.
            TreeNode tn = new TreeNode();
            tn.Text = "Child 1 of Root Parent";
            tn.NodeData = "SomeId=1001;Name=Play For Sport, Inc.";

            // Add the child to the root node.
            root.Nodes.Add( tn );

            // Create another child node.
            tn = new TreeNode();
            tn.Text = "Child 2 or Root Parent";
            tn.NodeData = "SomeId=1002;Name=Chip Oxendine";

            // Create a grandchild node and add it to its parent.
            TreeNode cn = new TreeNode();
            cn.Text = "Grandchild of Root Parent";
            cn.NodeData = "SomeId=1003;Name=Mike Elliott";
            tn.Nodes.Add( cn );

            // Add the child to the root node.
            root.Nodes.Add( tn );
            root.Expanded = true;

            // Add all the nodes to the tree view.
            this.tvControl.Nodes.Add( root );

            this.OverRideServerEvents();
        }

        private void OverRideServerEvents()
        {
            // Create and wire up the javascript event handlers.
            //
            string clickHandler = "TVIndexChanged();";
            this.tvControl.Attributes.Add( "onselectedindexchange",
                                                      clickHandler );

            clickHandler = "TVNodeExpand();";
            this.tvControl.Attributes.Add( "onexpand",
                                           clickHandler );

            clickHandler = "TVNodeCollapse();";
            this.tvControl.Attributes.Add( "oncollapse",
                                           clickHandler );

            clickHandler = "TVDoubleClick();";
            this.tvControl.Attributes.Add( "ondblclick",
                                           clickHandler );

            clickHandler = "TVRightClick();";
            this.tvControl.Attributes.Add( "oncontextmenu",
                                               clickHandler );
        }
    }
}

Page_Load回撥、事件或方法是頁面載入時呼叫的方法。在這個方法中,我們只是建立樹節點,提供節點的文字,以鍵/值對分隔的字串提供節點的NodeData屬性元資料,將節點新增到其父節點,最後將根節點新增到樹檢視中。

接下來,Page_Load方法將連線JavaScript攔截函式的工作委託給OverRideServerEvents方法。正如本文前面提到的,ASP。NET提供了一種機制,允許您向伺服器控制元件新增屬性。這個方法只是為我們想要在客戶端攔截的每個事件向TreeView控制元件新增屬性。我們新增屬性,這是樹檢視的伺服器端事件的正式名稱,然後將事件重定向到JavaScript函式,這就是它的全部內容。

當您觸發任何事件時,事件會被JavaScript函式攔截,目標樹節點的元資料會被解析並顯示在文字框中,攔截的事件的名稱也會顯示出來,這樣您就可以清楚地看到發生了什麼。

這是怎麼呢

StepDescription頁面已載入。樹檢視被建立。建立3A樹節點。設定樹節點的Test和NodeData屬性。樹節點被新增到其父節點的節點集合中。根樹節點被新增到樹檢視的節點集合中。

儘管我沒有在本文中介紹它,但是您可以通過儲存每個樹節點的狀態(展開/摺疊)在客戶機上完全管理樹檢視的狀態。這是將樹檢視的功能完全推送到客戶機所需要做的事情。否則,一旦引發回發,就會丟失哪些節點被展開、哪些節點被摺疊以及哪些節點被選中的狀態。這是一個稍微複雜一點的主題,我將在後續文章中介紹。

總結

將繁重的伺服器端事件轉移到客戶端以簡化ASP是非常可能的。NET應用程式,使用免費的MS TreeView控制元件。它非常簡單,其概念可以延伸到ASP.NET包含的大多數伺服器控制元件中。

歷史

  • 版本1.0.0.0

本文轉載於:http://www.diyabc.com/frontweb/news16602.html