Asp.Net 2.0 TreeView的Checkbox级联操作

1         前言

.Net Web应用, 有一个很大的苦恼就是没有太趁手的TreeView可用。微软的TreeView仅用作数据显示还行,但服务器控件不停的刷新太影响客户体验。商业化的TreeViewobout treeview / FlyTreeView / Infragistics NetAdvantage Treeview)都不错,特别是obout treeview短小精干讨人喜欢,但许可证是一个大障碍(公司一般不会花钱买的)。我一般而言,在TreeView做事情,用checkbox的时候较多,特别是父子节点的关联,因此,对Microsoft TreeView改造就从父子节点的关联开始。

2         ASP.Net 2.0 Treeview 简要分析

ASP.Net 2.0 Treeview吹的很不错,但客户端操作几乎为零。微软实现了一些客户端用的JavaScript TreeView.js,还不公开,藏在system.web.dll中,以资源的方式通过WebResource.axd来向客户端释放。仔细分析一下TreeView.js,会发现微软为TreeView自动生成的Html脚本结构如下:

<div>          //

      <table/> //节点

      <div/>   //节点的子节点,里面的内容是一个或多个<table/><div/>

</div>

因此,准确的说是<table/><div/>构成一个节点,但很难明确的在DOM中确定一个节点,原因如下:

1.        IDName是顺序排列的,命名规则如下: ID + “n” + 节点序号,例如 MyTreen0

商业的TreeView一般在ID中包含层次信息,如: MyTreeNode1_1_2 表示树的1.1.2那个节点,分析起来很容易

2.        上面描述的节点命名的ID,是分配给<table/>里的<A/>也就是显示 加号 减号的那个链接元素,由于该元素在<table/>中,因此给分析带来了难度

3.        叶子节点没有上面所描述的<table/>里的那个<A/> 无法分析(因此我自己JavaScript才会里出现A节点和Input节点,A节点就是有“树ID + “n” + 节点序号”为ID的链接元素,Input节点是<table/>里的Checkbox,命名规则为: ID + “n” + 节点序号 + “CheckBox”

3         自己写JavaScript

没办法,只有自己写JS函数来处理CheckBox的级联操作,其中用到了微软的TreeView.js WebForm.js,下载链接: TreeView2.rar

 加入方法如下:
*       TreeView加入OnClick事件

直接在TreeView的属性上加入:OnClick="OnTreeNodeChecked()"

或者:MyTree.Attributes.Add("OnClick", "OnTreeNodeChecked(event)");

*       这样写OnClick事件动作

<script language =javascript type="text/javascript"> 
    
function OnTreeNodeChecked() 
    

        
var element = window.event.srcElement; 
        
if (!IsCheckBox(element)) 
            
return

        
var isChecked = element.checked; 
        
var tree = TV2_GetTreeById(<%=SubSysTree.ClientID%>); 
        
var node = TV2_GetNode(tree,element); 

        TV2_SetChildNodesCheckStatus(node,isChecked); 

        
var parent = TV2_GetParentNode(tree,node); 
        TV2_NodeOnChildNodeCheckedChanged(tree,parent,isChecked); 

    }
 
</script> 

    TreeView2.js 也包含了一些对节点访问函数,可做其他用途。随着我自己需求的增加,我也会逐渐加入其他的一些功能进去。

Update:
    有朋友问到:在客户端如何取节点值?
     整个树的数据都作为XML放在ViewState中,节点的Value也就放在ViewState中,要分析它还有些麻烦。不过,可以看看这个工具(ViewStatueDecoder):http://www.pluralsight.com/tools.aspx,会有些启发

Update 20060624:
    针对shenghualuo实验不通的情况,我贴一个例子:
http://files.cnblogs.com/itrust/index.rar
    注意:由于例子源于我一个基于MonoRail的项目,因此Save不能使用

 
Copyright, 251   zhangtao.it@gmail.com, itrust.cnblogs.com        
posted @ 2006-04-03 11:44 251 阅读(10193) 评论(38)  编辑 收藏 网摘 所属分类: .Net

  回复  引用  查看    
#1楼2006-05-31 09:30 | 李.net      
我试了为什么老出错?
是不是只要把你的那个TreeView2.js包含进来,再加上那个onclick客户端事件就可以了?
还要不要包含TreeView.js 和 WebForm.js
??????????????

  回复  引用  查看    
#2楼[楼主]2006-06-09 10:40 | 251      
@李.net
出什么错?
只需要包含TreeView2.js
TreeView.js 和 WebForm.js 是在system.web.dll,你不用去管它

注意: TV2_GetTreeById("SubSysTree") 中 你需要写自己的TreeView控件的ID

  回复  引用    
#3楼2006-06-22 09:19 | shenghualuo[未注册用户]
我实验了一下,也报JS错误
我的代码如下
只有Html代码
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
<link href="TreeView2.js" type="text/jscript" rel="Stylesheet" />
</head>
<body >

<form id="form1" runat="server">
<div>
<script language ="javascript" type="text/javascript">
function OnTreeNodeChecked()
{
var element = element = window.event.srcElement;
if (!IsCheckBox(element))
return;

var isChecked = element.checked;
var tree = TV2_GetTreeById("TreeView1");
var node = TV2_GetNode(tree,element);

TV2_SetChildNodesCheckStatus(node,isChecked);

var parent = TV2_GetParentNode(tree,node);
TV2_NodeOnChildNodeCheckedChanged(tree,parent,isChecked);

}
</script>

<asp:TreeView ID="TreeView1" runat="server" ShowCheckBoxes="All" ShowLines="True" OnClick="OnTreeNodeChecked()" >
<Nodes>
<asp:TreeNode Text="世界" Value="世界">
<asp:TreeNode Text="亚洲" Value="亚洲">
<asp:TreeNode Text="中国" Value="中国">
<asp:TreeNode Text="苏州" Value="苏州"></asp:TreeNode>
<asp:TreeNode Text="上海" Value="上海"></asp:TreeNode>
</asp:TreeNode>
<asp:TreeNode Text="日本" Value="日本">
<asp:TreeNode Text="广岛" Value="广岛"></asp:TreeNode>
</asp:TreeNode>
<asp:TreeNode Text="韩国" Value="韩国"></asp:TreeNode>
</asp:TreeNode>
<asp:TreeNode Text="欧洲" Value="欧洲"></asp:TreeNode>
<asp:TreeNode Text="美洲" Value="美洲"></asp:TreeNode>
<asp:TreeNode Text="非洲" Value="非洲"></asp:TreeNode>
<asp:TreeNode Text="大洋洲" Value="大洋洲"></asp:TreeNode>
</asp:TreeNode>
</Nodes>
</asp:TreeView>
</div>
</form>
</body>
</html>

  回复  引用    
#4楼2006-06-22 09:20 | shenghualuo[未注册用户]
而且2005的TreeView好像不认OnClick这个函数
  回复  引用    
#5楼2006-06-22 12:15 | shenghualuo[未注册用户]
刚才实验了一下,好象有bug,我的层级如下,如果我全部勾选,然后取消日本的勾选,最上面的父亲节点世界也取消了,事实上不应该取消的,应该在这里加上判断
世界

亚洲

中国

苏州
上海

日本

广岛

韩国

欧洲
美洲
非洲
大洋洲


  回复  引用  查看    
#6楼[楼主]2006-06-23 10:07 | 251      
@shenghualuo
我有更新,根据你的例子上传了一个Demo

注意原则:
如果A节点下,有任意一个子节点位选择,则A不选择; 换言之,A节点被选的充要条件是:A节点的所有子节点都被选择

  回复  引用    
#7楼2006-06-26 08:59 | shenghualuo[未注册用户]
谢谢你的即时反馈,http://www.cnblogs.com/Files/itrust/index.aspx.rar
这个下载下来压缩包里面是0字节阿,可不可以发到我邮箱leo.luo@benq.com
上面提到的两个问题:
1:报JS错误是自己有个地方引用弄错了
2:
如果A节点下,有任意一个子节点位选择,则A不选择; 换言之,A节点被选的充要条件是:A节点的所有子节点都被选择
这个逻辑是不错,是否有办法可以实现我说的逻辑呢,我看了好多网站的例子也有我提到的这种逻辑,可能是和表的结构设计以及人的理解各有不同把,
就是A节点下面有B,C子节点,只有BC全都取消勾选,A才取消勾选,这种逻辑应该怎么写JS,

你有QQ或者MSN吗,加我吧,msn:leoluo1021@hotmail.com QQ:14421235 希望和你作个朋友!

  回复  引用    
#8楼2006-06-26 10:39 | shenghualuo[未注册用户]
刚才修改了一下代码,已经实现了我想要的效果,多谢LZ的鼎力相助,
还有个问题想问一下 ,如何去掉节点上的link 阿,不想有鼠标放上去可以点连接的,就直接是问题就好,好像属性里面找不到设置的

  回复  引用  查看    
#9楼[楼主]2006-06-26 13:30 | 251      
@shenghualuo
EnableClientScript = false

  回复  引用    
#10楼2006-06-27 09:17 | shenghualuo[未注册用户]
可是如果设置 EnableClientScript="false" 会将所有的Js都禁用掉阿,之前实现勾选checkbox不刷新的这段JS也用不了阿,有没有什么两全其美的办法呢
  回复  引用  查看    
#11楼2006-08-28 17:05 | 晓风残月      
不错,正是偶想要的,
谢谢LZ^_^

  回复  引用    
#12楼2006-10-17 10:03 | nontrick[未注册用户]
试试这个怎样,:)
<script language ='javascript' type='text/javascript'>
function OnTreeNodeChecked()
{
var ele = event.srcElement;
if(ele.type=='checkbox')
{
var childrenDivID = ele.id.replace('CheckBox','Nodes');
var div = document.getElementById(childrenDivID);
if(div==null)return;
var checkBoxs = div.getElementsByTagName('INPUT');
for(var i=0;i<checkBoxs.length;i++)
{
if(checkBoxs[i].type=='checkbox')
checkBoxs[i].checked=ele.checked;
}
}
}
</script>

  回复  引用    
#13楼2006-10-18 17:07 | 锦[匿名][未注册用户]
感动一下 多谢多谢 多谢多谢 多谢多谢 多谢多谢
  回复  引用    
#14楼2006-10-31 14:14 | 252[未注册用户]
朋友,2005的TreeView好像不认OnClick这个函数啊,加入以后没有反应。
  回复  引用    
#15楼2007-01-05 10:29 | rainyfox[未注册用户]
可不可以让树变成单选啊
  回复  引用    
#16楼2007-01-05 10:46 | sky[匿名][未注册用户]
怎样在客户端,取到对应得值?
  回复  引用    
#17楼2007-01-29 18:54 | liwenliang[未注册用户]
在vs2005中的asp.net上的webfrom上的treeview控件,没有OnClick事件,怎么实现?
我的问题是:从存储过程获得数据放到DATASET上,把数据在treeview上显示,可是在我点击节点时候,界面老是刷新.怎么才能解决这个页面刷新的问题呢?
敬请高手帮忙 谢谢

  回复  引用    
#18楼2007-02-01 02:47 | jinglecat
@liwenliang
someTreeNode.NavigatorUrl = "javacript:void(0)";

  回复  引用    
#19楼2007-02-13 16:26 | zaifei[未注册用户]
我想在客户端获取到TreeView的value,应该怎么做呢???
  回复  引用    
#20楼2007-02-19 17:01 | jinglecat[未注册用户]
好像没有办法取道,value应该是存到了ViewState中
  回复  引用    
#21楼2007-03-16 03:43 | 爱网[未注册用户]
Server:
node.NavigateUrl= r["Url"].ToString() + "&menuNodeID=" + node.Value;
//"&menuNodeID=" + node.Value; 一般不会影响原链接的打开

Client:
//在相关事件中放入:
var url = event.srcElement.href;
var val=url.substring(url.indexOf("&menuNodeID=")+"&menuNodeID=".length);
// alert(val); //val就是node.Value

  回复  引用    
#22楼2007-03-16 16:27 | zhul[未注册用户]
为什么我的提示“缺少对象”
  回复  引用  查看    
#23楼2007-03-16 16:36 | 爱网2008      
Server:
node.NavigateUrl= r["Url"].ToString() + "&menuNodeID=" + node.Value;
//"添加&menuNodeID=" + node.Value; 一般不会影响原链接的打开

Client:
//在相关事件中放入:
var url = event.srcElement.href;
var val=url.substring(url.indexOf("&menuNodeID=")+"&menuNodeID=".length);
alert(val); //val就是node.Value

可参考:
http://www.cnblogs.com/lovenets2008/archive/2007/03/16/677427.html">http://www.cnblogs.com/lovenets2008/archive/2007/03/16/677427.html

  回复  引用    
#24楼2007-03-19 00:32 | jinglecat
@爱网2008
的确是个不错的方法!
而且,对于只需要客户端JS处理的TreeView, 而不是用来导航连接的来说,就可以简单的设置
node.NavigateUrl = "#nodevalue=somevalue";
or
node.NavigateUrl = "javascript:void('somevlaue')";

然后客户端分析取道 somvalue

  回复  引用  查看    
#25楼2007-03-19 02:27 | 晓风残月      
@zhul
看看我的Demo吧,也许有帮助

@爱网2008
呵呵,我实现了,thx!

@rainyfox
TreeView 默认就是单选的,我的Demo中对LZ的TreeView2.js加了单选判断

参考:
http://www.cnblogs.com/Jinglecat/archive/2007/03/19/679313.html">http://www.cnblogs.com/Jinglecat/archive/2007/03/19/679313.html

  回复  引用  查看    
#26楼2007-03-26 13:21 | jiandan      
非常有用.谢谢
  回复  引用    
#27楼2007-04-27 12:59 | lv[未注册用户]
怎样通过js添加或删除节点啊??
  回复  引用  查看    
#28楼2007-04-28 00:23 | 爱网2008      
function deletemenuitem(){
if(selnodevalue){
top.mainFrame.location.href="TREEMENU/Delete.aspx?id="+selnodevalue;
location.href=location.href;
}
}

  回复  引用    
#29楼2007-06-20 10:29 | wschacker[未注册用户]
@shenghualuo
能不能分享一下你实现的逻辑效果的js代码啊?

  回复  引用    
#30楼2007-07-31 20:58 | 旧瓶装新酒[未注册用户]
试用了一下,不错,呵呵,谢谢!

  回复  引用    
#31楼2007-08-07 17:35 | 过路人[未注册用户]
IE下面基本好用,但是FF下就不灵了!希望作者能够发布更好的版本!
  回复  引用    
#32楼2007-09-06 17:33 | 兵[未注册用户]
调试不通过的,请查看源文件中treeview的id值的编码规则--自己经验之谈。
  回复  引用    
#33楼2008-02-28 10:39 | 何德勇[未注册用户]
谢谢你们!,你们都是牛人
  回复  引用    
#34楼2008-04-10 16:30 | dezwen1[未注册用户]
使用母版会出现“缺少对象“错误。不知道什么回事!!
  回复  引用    
#35楼2008-04-10 17:14 | dezwen1[未注册用户]
弄了一个下午,原来是一个低级错误,并不是说使用母版就不行,是我在取TreeView的ID时的问题,哈哈!
楼主在var tree = TV2_GetTreeById("SubSysTree"); 这句代码里使用的是TreeView的服务器端控件ID,但在生成客户端代码后就不一定是这个ID了。为了保险起见,请使用下面这个作法:
var tree = TV2_GetTreeById("<%=SubSysTree.ClientID%>");

  回复  引用    
#36楼2008-08-30 12:00 | 哦可靠[未注册用户]
怎么附件载不下来啊
  回复  引用  查看    
#37楼2009-02-07 14:28 | 长河落日      
高人
  回复  引用  查看    
#38楼2009-03-20 23:24 | 殷良胜      
不错



发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 365439




相关文章:

相关链接: