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的公共方法和属性都作了一个定义,如下所示

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
}