代码改变世界

【ASP.NET 控件浅谈】 之 TreeView 操作(带多选操作)

2011-12-08 16:30  木+头  阅读(665)  评论(0编辑  收藏  举报

最近公司项目方面要使用带有复选框的Tree,不用不知道一用吓一跳,微软的TreeView也可以有复选框

但是很遗憾的事情是它的兼容性不是很好,貌似在火狐下面都打不开节点,今天的主要内容不是他得兼容性

而是有复选后的一些易用性,和Value取值的问题

有了这个,如果不需要回传的话,我们就可用禁用TreeView的ViewState了,我们就可用不用点一下就刷新下了

我们更加不需要为了一个Value而苦恼了

 

1. 子树的复选框根据父亲的复选框的状态改变而改变(类似全选)

该功能请参照贴出的JS代码

2.子树的节点状态改变后,如果同级节点有一个以上的选项选中则父节点为选中状态否则复选项为未选中状态

 该功能请参照贴出的JS代码

3.TreeView在客户端获取Value

由于点击CheckBox时没有回传,或者我们不需要他回传,等等很多情况下我们可能需要直接在客户端知道TreeView的当前所有选中的复选框的值

但是TreeView不是很给力,根据他自动生成的代码我们可以看得出,他把值写死在节点的链接的href里,如:__doPostBack('Tree','Root','Value');

当然你一定要用分解字符串的方式来取值,也没有关系,不过这里有一个相对简单点得方法,可以参考一下

我的做法是

将子节点的NavigateUrl的属性设置成带值的样子,我是这么设置的

TreeNode userNode = new TreeNode("用户名称","用户编号");
userNode.ShowCheckBox = true;
userNode.NavigateUrl = "#" +"用户编号";

这样子我们就将值绑定在页面里了

(注意:貌似这里一旦设置NavigateUrl,可能点击就不会触发回传事件了,如果你要回传数据,可能要想其他方法了,当然方法肯定是有的)


当然光绑定是没有用的,我们还要最核心的客户端代码来处理

    <script type='text/javascript'>
// 回溯上面的复选框
function SetFeedBackStatus(divContainer, isChecked) {
var prevDiv = divContainer.parentNode;
if (!prevDiv || prevDiv.id == '')
return false;

var hasChecked = false;
for (var i = 0; i < prevDiv.children.length; i++) {
var childEl = prevDiv.children[i];
var tagName = childEl.tagName.toLowerCase();
if (tagName == 'table') { // 选项
var cells = childEl.cells;
var childCheckbox = cells[cells.length - 1].childNodes[0];
if (childCheckbox.checked) {
hasChecked = true;
break;
}
}
}

var prevCheckBoxId = prevDiv.id.replace('Nodes', 'CheckBox');
var prevCheckBoxEl = document.getElementById(prevCheckBoxId);
if (prevCheckBoxEl) {
prevCheckBoxEl.checked = hasChecked;
SetFeedBackStatus(prevDiv);
}
}
/*
* 找到同级别的叶子里是否有选中的,如果存在选中的则不进行任何操作,否则将上一级根设置为未选中
* 判断上一级跟的同级别根是否存在选中的,如果不存在选中的则将上上级根设置成未选中状态
*/
function feedBackCheckbox(checkedObj) {
var divEl = checkedObj.parentNode.parentNode.parentNode.parentNode;// 装CheckBox的Table容器 //.parentNode; // 主CheckBox容器
SetFeedBackStatus(divEl);
}

     // 遍历子复选容器循环赋值
function setCheckBoxStatus(divContainer, isChecked) {
var divEl = typeof (divContainer) == 'object' ? divContainer : document.getElementById(divContainerId);
if (divEl && divEl.children) {
for (var i = 0; i < divEl.children.length; i++) {
var childEl = divEl.children[i];
var tagName = childEl.tagName.toLowerCase();
if (tagName == 'table') // 选项容器
{
var cells = childEl.cells;
var childCheckbox = cells[cells.length - 1].childNodes[0];
childCheckbox.checked = isChecked;
}
else // 选项集合容器
{
setCheckBoxStatus(childEl, isChecked);
}
}
}
}

// 遍历选子复选框
function setChildCheckbox(checkedObj) {
var childsContainerId = checkedObj.id.replace('CheckBox', 'Nodes');
var childsContainer = document.getElementById(childsContainerId);
setCheckBoxStatus(childsContainer, checkedObj.checked);
}

// 设置超链接事件,让其点击能够与checkBox绑定
function setLinksTagClick(checkedObj) {
checkedObj.parentNode.children[1].onclick = function() {
var checkBoxEl = window.event.srcElement.parentNode.children[0];
checkBoxEl.checked = !checkBoxEl.checked;
feedBackCheckbox(checkBoxEl);
setChildCheckbox(checkBoxEl);
return false;
}
}

// 获取复选列表
function GetCheckBoxList() {
var rst = [];
var inputEl = document.getElementsByTagName("input");
for (var i = 0; i < inputEl.length; i++) {
if (inputEl[i] && inputEl[i].type == 'checkbox')
rst.push(inputEl[i]);
}
return rst;
}

// 获取复选框选中项
function GetCheckedKeyValues() {
var returnValue =
{
Keys: [],
Values: [],
length: function() {
return this.Keys.length;
},
put: function(key, val) {
var hasKey = this.containsKey(key);
var insertIndex = hasKey == -1 ? this.length() : hasKey;
this.Keys[insertIndex] = key;
this.Values[insertIndex] = val;
},
get: function(key) {
return this.Values[this.containsKey(key)];
},
remove: function(key) {
throw new Error("not impl!");
},
containsKey: function(key) {
for (var i = 0; i < this.length(); i++) {
if (key == this.Keys[i]) return i;
}
return -1;
}
};
var chkList = GetCheckBoxList();
for (var i = 0; i < chkList.length; i++) {
if (chkList[i].checked) { // 如果该项被选中,则将关联的链接标签找出来,存入返回值中
var linkEl = chkList[i].parentNode.children[1];
var key = linkEl.href.substring(linkEl.href.indexOf("#")+1);
if (key != "")
returnValue.put(key, linkEl.childNodes[0].nodeValue); // 由于名字可能有重复的,所以只能作为值来存放
}
}
return returnValue;
}

// 绑定所有的CheckBox事件
(function BindClientCheckBoxEvent() {
var chkList = GetCheckBoxList();
for (var i = 0; i < chkList.length; i++) {
setLinksTagClick(chkList[i]);
chkList[i].onclick = function() {
var checkBoxEl = window.event.srcElement;
feedBackCheckbox(checkBoxEl);
setChildCheckbox(checkBoxEl);
}
}
})();
</script>

 

 

 

我贴得代码中可能不是很和谐,主要是我是在一个只有一棵树的页面中做到测试,并未考虑有其他CheckBox,可能在一个多树的页面就会有一点点问题

如果有其他CheckBox的话,只需要在绑定事件的时候不但根据类型是否为CheckBox 而且还要根据Id存在的TreeView的编号来查找

当然这只是我想象中得方法

非常感谢各路大仙的光临,非常期望各路大仙的指教