介绍
这篇文章演示了如何使用免费的来自微软的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:buildMicrosoft.Web.UI.WebControls.dll @IEWebControls.rsp
除非将css .exe编译实用程序放在主路径中,或者将可执行文件的副本放在system或system32目录中,否则.bat文件将找不到编译实用程序,并以静默方式失败。
要纠正这个问题,可以修改.bat文件,使其具有csc.exe编译工具的完整路径,如下所示(位置和版本可能在您的机器上不同):
C:WindowsMicrosoft.NETFrameworkv1.14322csc.exe /out:buildMicrosoft.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