TreeView第三种状态的另类实现
转自:http://blog.csdn.net/am2004/archive/2007/05/22/1621349.aspx
缘起:最近给一个WinForm项目做权限设置,需要用到树形控件(TreeView)。设置TreeView的CheckBoxes属性为true时,树形控件的每个节点前会出现一个选择框。但选择框只有两种显示外观,即选中(框中有勾)和未选中。相信很多朋友也希望能够有第三种显示外观,当节点的子节点部分选中时使用。去网上寻求方案,多是建议自己开发继承自TreeView的自定控件,在自定控件扩展属性以实现三种状态。不讨论方案的优劣性,能否有其他的方案可以快速实现?
缘起:最近给一个WinForm项目做权限设置,需要用到树形控件(TreeView)。设置TreeView的CheckBoxes属性为true时,树形控件的每个节点前会出现一个选择框。但选择框只有两种显示外观,即选中(框中有勾)和未选中。相信很多朋友也希望能够有第三种显示外观,当节点的子节点部分选中时使用。去网上寻求方案,多是建议自己开发继承自TreeView的自定控件,在自定控件扩展属性以实现三种状态。不讨论方案的优劣性,能否有其他的方案可以快速实现?
思路:TreeView有ImageList和ImageIndex属性,可以用该属性为每个节点定义显示的图像。如果我们自备三种状态的显示图像,在NodeMouseClick事件中控制节点应该显示那个图像,是不是也可以呢?答案是肯定的,而且不算复杂。
要点之一:需设置TreeView的CheckBoxes属性为false,准备三个图片(图片地址:http://album.pixplayer.com/208003_242/),我们用ImageIndex等于0、1、2分别代表该节点未选中、选中、子节点部分选中三种状态,不再考虑使用节点的Checked属性。最终效果图片(图片地址:http://album.pixplayer.com/208003_242/)
要点之二:我们编程之前需要确定任意某个节点被点击时(NodeMouseClick事件)的处理规则,规则明朗后程序就基本上写出来了。
//规则1:取消选定
//规则1.1:检查是否有子节点,需清除所有子节点的选定状态;
//规则1.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
//规则2:选定
//规则2.1:检查是否有子节点,设置所有子节点为选定状态
//规则2.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
|
代码参考:
//设置选定和取消选定后的显示图像
private void ButtonsTree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
//规则1:取消选定
//规则1.1:检查是否有子节点,需清除所有子节点的选定状态;
//规则1.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
//规则2:选定
//规则2.1:检查是否有子节点,设置所有子节点为选定状态
//规则2.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
if (e.Node.ImageIndex == 1)
{
e.Node.SelectedImageIndex = 0;
e.Node.ImageIndex = 0;
SetNodeImg11(e.Node);
SetNodeImg12(e.Node);
}
else
{
e.Node.SelectedImageIndex = 1;
e.Node.ImageIndex = 1;
SetNodeImg21(e.Node);
SetNodeImg22(e.Node);
}
}
//设置节点选定状态:规则.1:检查是否有子节点,需清除所有子节点的选定状态;
private void SetNodeImg11(TreeNode tn)
{
foreach (TreeNode t in tn.Nodes)
{
t.SelectedImageIndex = 0;
t.ImageIndex = 0;
if (t.Nodes.Count != 0)
{
SetNodeImg11(t);
}
}
}
//设置节点选定状态:规则.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
private void SetNodeImg12(TreeNode tn)
{
if (tn.Parent == null)
return;
int Img0Num = 0;
int Img1Num = 0;
int Img2Num = 0;
//统计兄弟节点中选中情况
foreach (TreeNode t in tn.Parent.Nodes)
{
if (t.ImageIndex == 0)
Img0Num++;
if (t.ImageIndex == 1)
Img1Num++;
if (t.ImageIndex == 2)
Img2Num++;
}
//如果兄弟节点中选中和未选中都有
if ((Img2Num != 0) || ((Img0Num != 0) && (Img1Num != 0)))
{
tn.Parent.SelectedImageIndex = 2;
tn.Parent.ImageIndex = 2;
}
else
{
tn.Parent.StateImageIndex = 0;
tn.Parent.ImageIndex = 0;
}
//递归
SetNodeImg12(tn.Parent);
}
//设置节点选定状态:规则.1:检查是否有子节点,设置所有子节点为选定状态
private void SetNodeImg21(TreeNode tn)
{
foreach (TreeNode t in tn.Nodes)
{
t.SelectedImageIndex = 1;
t.ImageIndex = 1;
if (t.Nodes.Count != 0)
{
SetNodeImg21(t);
}
}
}
//设置节点选定状态:规则.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
private void SetNodeImg22(TreeNode tn)
{
if (tn.Parent == null)
return;
int Img0Num = 0;
int Img1Num = 0;
int Img2Num = 0;
//统计兄弟节点中选中情况
foreach (TreeNode t in tn.Parent.Nodes)
{
if (t.ImageIndex == 0)
Img0Num++;
if (t.ImageIndex == 1)
Img1Num++;
if (t.ImageIndex == 2)
Img2Num++;
}
//如果兄弟节点中选中和未选中都有
if ((Img2Num != 0) || ((Img0Num != 0) && (Img1Num != 0)))
{
tn.Parent.SelectedImageIndex = 2;
tn.Parent.ImageIndex = 2;
}
else if ((Img1Num == 0) && (Img2Num == 0))
{
tn.Parent.SelectedImageIndex = 0;
tn.Parent.ImageIndex = 0;
}
else
{
tn.Parent.StateImageIndex = 1;
tn.Parent.ImageIndex = 1;
}
//递归
SetNodeImg22(tn.Parent);
}
|