TreeView第三种状态的另类实现

转自:http://blog.csdn.net/am2004/archive/2007/05/22/1621349.aspx

缘起:
最近给一个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);
        }
 
 
 
posted @ 2007-12-03 13:19  jenner  阅读(669)  评论(0编辑  收藏  举报