1. 前言
很久没有用2003,本来正研究2008的新功能和framework3.5的新特性,由于项目的需要,重新用回2003。装上2003后,界面土的掉渣的也就忍了,使用上也有诸多不便,比如智能感知方面。控件也很少,比如常用的treeview,死活找不着,后来经过遥远的回忆,依稀记起那个仿佛需要另外安装。于是上网搜索下载IE Web Controls,安装,vs.net命令行运行安装目录下build.bat,将runtime里的所有文件拷贝至默认网站下"webctrl_client\1_0"中,在IDE中的工具栏中添加在编译好的dll,终于出现了treeview,翻倒自己原来写过的treeview代码,拷贝粘贴完事,欣喜若狂。生活不如意的事十有八九,这句话谁说的,真TMD太对了。运行之后,发现vs2005上对treeview操作的javascript脚本在vs2003完全不能用,于是就有了下面的事。
2. XML数据绑定
2005上treeview与xml绑定非常灵活,这里就不详述了,还是契合主题,讲讲2003下的xml数据绑定。首先创建一个xml文件,如下所示,必须以TreeNodes为根,同时所有的节点都以treenode为tag。
<?xml version="1.0" encoding="utf-8" ?>
<TREENODES>
<treenode text="test">
<treenode text="test">
</treenode >
<treenode text="test">
</treenode >
<treenode text="test">
</treenode >
</treenode >
<treenode text="test"></treenode>
</TREENODES>
数据绑定时,使用如下代码
MessageTypeTree.TreeNodeSrc="MessageTypeData.xml";
MessageTypeTree.DataBind();
3. 使用checkbox
如果要在节点中使用checkbox,必须在各个treenode设置node.CheckBox = true,才能实现。下面的代码使用了一个递归函数实现对整个treeview所有节点的checkbox设置。
private void SetCheckBox(TreeNode pNode)
{
if(pNode == null)
{
foreach(TreeNode node in MessageTypeTree.Nodes)
{
node.CheckBox = true;
node.Expanded = true;
SetCheckBox(node);
}
}
else
{
foreach(TreeNode node in pNode.Nodes)
{
node.CheckBox = true;
node.Expanded = true;
SetCheckBox(node);
}
}
}
4. 操作treeview的checkbox
4.1. 功能点分析
总结一下,主要实现如下效果:
(1) 选择父节点时,子节点全部选上。
(2) 当子节点全部选上时,父节点应选上。
(3) 点击全选时,将所有的节点选上
(4) 点击反选时,将没有选中的节点选上,将已选中的节点清除,同时注意判断子节点没有全部选上时,父节点不能选上。
4.2. 实现思路
要操作checkbox,肯定要在客户端实现,大量使用js脚本是无法避免了。 2003中的treeview与2005的treeview实现机制有所不同,直接利用js的document.getElementByTag(“input”)的方法是不能获取到的,但天无绝人之路,好在treeview公开了所有的源码。客户端的源码在默认网站下"webctrl_client\1_0"中,安装时拷贝过去的。打开目录,找到名为treeview.htc的文件。服务器端的源码在安装目录下的Src目录中。
源码中的开头对treeview的公共方法和属性都作了一个定义,如下所示
1<public:component tagname=treeview literalcontent=true>
2 <public:attach event=oncontentready onevent="oncontentready()" />
3 <public:attach event=ondocumentready onevent="ondocumentready()" />
4 <public:attach event="onscroll" onevent="onScroll()" />
5 <public:event name="onexpand" id="_tvevtExpand" />
6 <public:event name="oncollapse" id="_tvevtCollapse" />
7 <public:event name="onselectedindexchange" id="_tvevtSelect" />
8 <public:event name="oncheck" id="_tvevtCheck" />
9 <public:event name="onfirequeuedevents" id="_tvevtFireQueuedEvents" />
10 <public:event name="onnodebound" id="_tvevtNodeBound" />
11 <public:event name="onnodetypesbound" id="_tvevtNodeTypesBound" />
12 <public:event name="onhover" id="_tvevtHover" />
13 <public:event name="onunhover" id="_tvevtUnhover" />
14 <public:property name="clickedNodeIndex" GET="getClickedNodeIndex" />
15 <public:property name="defaultStyle" id="_tvpropDefaultStyle" GET="getDefaultStyle" PUT="setDefaultStyle" />
16 <public:property name="hoverStyle" id="_tvpropHoverStyle" GET="getHoverStyle" PUT="setHoverStyle" />
17 <public:property name="selectedStyle" id="_tvpropSelectedStyle" GET="getSelectedStyle" PUT="setSelectedStyle" />
18 <public:property name="childType" id="_tvpropChildType" GET="getChildType" PUT="setChildType" />
19 <public:property name="imageUrl" id="_tvpropImageUrl" GET="getImageUrl" PUT="setImageUrl" />
20 <public:property name="expandedImageUrl" id="_tvpropExpandedImageUrl" GET="getExpandedImageUrl" PUT="setExpandedImageUrl" />
21 <public:property name="selectedImageUrl" id="_tvpropSelectedImageUrl" GET="getSelectedImageUrl" PUT="setSelectedImageUrl" />
22 <public:property name="target" id="_tvpropTarget" GET="getTarget" PUT="setTarget" />
23 <public:property name="treeNodeSrc" id="_tvpropTreeNodeSrc" GET="getTreeNodeSrc" PUT="setTreeNodeSrc" />
24 <public:property name="treeNodeXsltSrc" id="_tvpropTreeNodeXsltSrc" GET="getTreeNodeXsltSrc" PUT="setTreeNodeXsltSrc" />
25 <public:property name="selectExpands" id="_tvpropSelectExpands" GET="getSelectExpands" PUT="setSelectExpands" />
26 <public:property name="expandLevel" id="_tvpropExpandLevel" GET="getExpandLevel" PUT="setExpandLevel" />
27 <public:property name="autoSelect" id="_tvpropAutoSelect" GET="getAutoSelect" PUT="setAutoSelect" />
28 <public:property name="treeNodeTypeSrc" id="_tvpropTreeNodeTypeSrc" GET="getTreeNodeTypeSrc" PUT="setTreeNodeTypeSrc" />
29 <public:property name="showLines" id="_tvpropShowLines" GET="getShowLines" PUT="setShowLines" />
30 <public:property name="showPlus" id="_tvpropShowPlus" GET="getShowPlus" PUT="setShowPlus" />
31 <public:property name="showToolTip" id="_tvpropShowToolTip" GET="getShowToolTip" PUT="setShowToolTip" />
32 <public:property name="indent" id="_tvpropIndent" GET="getIndent" PUT="setIndent" />
33 <public:property name="selectedNodeIndex" id="_tvpropSelectedNodeIndex" GET="getSelectedNodeIndex" PUT="setSelectedNodeIndex" />
34 <public:property name="systemImagesPath" id="_tvpropSystemImagesPath" GET="getSystemImagesPath" PUT="setSystemImagesPath" />
35 <public:method name="queueEvent" />
36 <public:method name="getTreeNode" />
37 <public:method name="addAt" />
38 <public:method name="createTreeNode" />
39 <public:method name="getTreeNodeType" />
40 <public:method name="createTreeNodeType" />
41 <public:method name="addTreeNodeType" />
42 <public:method name="add" />
43 <public:method name="databind" />
44 <public:method name="databindTypes" />
45 <public:method name="getChildren" />
46
47</public:component>
可以直接通过treeview对象调用这些方法,主要用到的方法和属性如下表所示
名称 | 输入参数 | 返回值 | 描述 |
clickedNodeIndex | Null | 索引值,例如1.0.1 | 获取当前点击的node索引值 |
getChildren | Null | 节点数组 | 获取下一级的节点数组 |
getTreeNode | NodeIndex | TreeNode对象 | 根据索引获取树节点 |
除了treeview对象,涉及到的对象还有TreeNode对象,TreeNode对象主要用到的方法和属性如下表所示
名称 | 输入参数 | 返回值 | 描述 |
getAttribute | 属性名称,如”text” | 字符型,如test | 获取当前节点的属性值 |
setAttribute | 属性名称和值 | Null | 设置当前节点的属性值 |
getNodeIndex | Null | 索引值 | 获取当前节点的索引值 |
getChildren | Null | 节点数组 | 获取下一级的节点数组 |
getParent | Null | TreeNode或Tree对象 | 获取父对象 |
现在万事俱备,只欠东风。在服务器端,设置treeview的oncheck事件激发脚本代码,如下所示
MessageTypeTree.Attributes["oncheck"] = "javascript:SelectCheckBox();";
客户端实现如下所示
1//单击选择
2 function SelectCheckBox()
3 {
4 if (MessageTypeTree.clickedNodeIndex != null)
5 {
6 var node = MessageTypeTree.getTreeNode(MessageTypeTree.clickedNodeIndex);
7 setChildren(node);
8 setParent(node);
9 }
10 setLblTxt(getAllSelectedChx());
11 }
12 function setChildren(node)
13 {
14 var children = node.getChildren();
15 for(var i=0;i<children.length;i++)
16 {
17 var checked = node.getAttribute("checked");
18 children[i].setAttribute("checked",checked);
19 setChildren(children[i]);
20 }
21 }
22 function setParent(node)
23 {
24 var parentNode = node.getParent();
25 if(parentNode != null)
26 {
27 var children = parentNode.getChildren();
28 var checked = false;
29
30 if(children.length == 1)
31 checked = children[0].getAttribute("checked");
32 else
33 {
34 for(var i=0;i<children.length-1;i++)
35 {
36 var checked1 = children[i].getAttribute("checked");
37 var checked2 = children[i+1].getAttribute("checked");
38 if(checked1 != checked2)
39 {
40 checked = false;
41 break;
42 }
43 checked = checked1;
44 }
45 }
46 parentNode.setAttribute("checked",checked);
47 setParent(parentNode);
48 }
49 }
50 //全选
51 function selectAll()
52 {
53 var chx = document.getElementById("SelectAllChx");
54 var children = MessageTypeTree.getChildren();
55 for(var i=0;i<children.length;i++)
56 {
57 children[i].setAttribute("checked",chx.checked);
58 setChildren(children[i]);
59 }
60 setLblTxt(getAllSelectedChx());
61 }
62 //反选
63 function selectOpposition()
64 {
65 var children = MessageTypeTree.getChildren();
66 for(var i=0;i<children.length;i++)
67 {
68 var checked = children[i].getAttribute("checked");
69 children[i].setAttribute("checked",!checked);
70 setChildrenOpposition(children[i]);
71 }
72 setLblTxt(getAllSelectedChx());
73 }
74 function setChildrenOpposition(node)
75 {
76
77 var children = node.getChildren();
78 for(var i=0;i<children.length;i++)
79 {
80 var checked = children[i].getAttribute("checked");
81 children[i].setAttribute("checked",!checked);
82 setChildrenOpposition(children[i]);
83 }
84 setParent(node);
85 }
86 //获取所有checkbox的值
87 function getAllSelectedChx()
88 {
89 var children = MessageTypeTree.getChildren();
90 var text = "";
91 for(var i=0;i<children.length;i++)
92 {
93 var checked = children[i].getAttribute("checked");
94 if(checked == true)
95 text = addText(text,children[i].getAttribute("text"));
96 else
97 text = getChildrenSelectedChx(text,children[i]);
98 }
99 return text;
100 }
101 function addText(text,addTxt)
102 {
103 text = trim(text);
104 addTxt = trim(addTxt);
105 if( text == null || text == "")
106 text += addTxt;
107 else
108 text += ";"+addTxt;
109 return text;
110 }
111 function trim(str)
112 {
113 return str.replace(/(^\s*)|(\s*$)/g,"");
114 }
115 function getChildrenSelectedChx(text,node)
116 {
117 var children = node.getChildren();
118 for(var i=0;i<children.length;i++)
119 {
120 var checked = children[i].getAttribute("checked");
121 if(checked == true)
122 {
123 var tempTxt = children[i].getAttribute("text");
124 text = addText(text,getParentNodeTxt(children[i],tempTxt));
125 }
126 else
127 getChildrenSelectedChx(text,children[i]);
128 }
129 return text;
130 }
131 function getParentNodeTxt(node,text)
132 {
133 var parentNode = node.getParent();
134 if(parentNode != null)
135 {
136 text = trim(parentNode.getAttribute("text"))+ "."+trim(text);
137 text = getParentNodeTxt(parentNode,text);
138 }
139 return text;
140 }
141 //设置label的预览值
142 function setLblTxt(text)
143 {
144 document.getElementById("SelectNodesLbl").innerText = text;
145 }