自定义 TreeView 第三种状态(C#自定义控件)

本文核心部分采用 http://blog.csdn.net/am2004/article/details/1621349 此网站代码.
在增加了部份事件的同时,将点击图片更改节点选中状态 这一小地方作了改进.
目前点击节点前的加减符号不会更改节点状态.
 
此处有添加一个含有三个图片的ImageList 控件,里面 0 不选 1 部分选 2 选中 三个ICO 文件,大家可网上下载.
using System.Drawing;
using System.Windows.Forms;

namespace SimpleCustomControl
{
    public partial class MyTreeView : TreeView
    {
        private int imageWidth = 0x12;

        public MyTreeView()
        {
            InitializeComponent();
            // 如果更改 ImageList 中图片大小,此处设置可能有用.未测试.可注释掉.
            imageWidth = imageList1.ImageSize.Width + 2;
        }

        //规则1:取消选定
        //规则1.1:检查是否有子节点,需清除所有子节点的选定状态;
        //规则1.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
        //规则2:选定
        //规则2.1:检查是否有子节点,设置所有子节点为选定状态
        //规则2.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
        /// <summary>
        /// 鼠标点击节点触发事件
        /// </summary>
        private void MyTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                Rectangle rc = e.Node.Bounds;
                rc = new Rectangle(rc.X - imageWidth, rc.Y, rc.Width + imageWidth, rc.Height);
                if (rc.Contains(e.Location))
                {
                    if (e.Node.Level == 0 && e.Node.Index == 0)
                        NodeUnSelected();
                    else
                        NodeClick(e.Node);
                }
            }
        }

        /// <summary>
        /// 节点点击
        /// </summary>
        /// <param name="tn">点击的节点</param>
        public void NodeClick(TreeNode tn)
        {
            if (tn.ImageIndex == 2)
            {
                NodeUnSelected(tn);
            }
            else
            {
                NodeSelected(tn);
            }
        }

        /// <summary>
        /// 不管现在节点状态
        /// 将节点设置为选中
        /// </summary>
        /// <param name="tn">待更改状态的节点</param>
        public void NodeSelected(TreeNode tn)
        {
            tn.SelectedImageIndex = 2;
            tn.ImageIndex = 2;
            SetNodeImg21(tn);
            SetNodeImg22(tn);
        }

        /// <summary>
        /// 不管现在节点状态
        /// 去掉节点选中状态
        /// </summary>
        /// <param name="tn">待更改状态的节点</param>
        public void NodeUnSelected(TreeNode tn)
        {
            tn.SelectedImageIndex = 0;
            tn.ImageIndex = 0;
            SetNodeImg11(tn);
            SetNodeImg12(tn);
        }

        /// <summary>
        /// 查找节点状态 是否被选中
        /// </summary>
        /// <param name="tn">查看的节点</param>
        /// <returns>节点是否被选中</returns>
        public bool NodeIsChecked(TreeNode tn)
        {
            if (tn.ImageIndex == 1 || tn.ImageIndex == 2)
                return true;
            return false;
        }

        public CheckState NodeCheckState(TreeNode tn)
        {
            switch (tn.ImageIndex)
            {
                case 1:
                    return CheckState.Indeterminate;
                case 2:
                    return CheckState.Checked;
                case 0:
                default:
                    return CheckState.Unchecked;
            }
        }

        /// <summary>
        /// 将所有子节点全不选
        /// </summary>
        public void NodeUnSelected()
        {
            foreach (TreeNode tn in this.Nodes)
            {
                NodeUnSelected(tn);
            }
        }

        /// <summary>
        /// 将所有子节点全选
        /// </summary>
        public void NodeSelected()
        {
            foreach (TreeNode tn in this.Nodes)
            {
                NodeSelected(tn);
            }
        }

        //设置节点选定状态:
        //规则.1:检查是否有子节点,需清除所有子节点的选定状态;
        void SetNodeImg11(TreeNode tn)
        {
            foreach (TreeNode t in tn.Nodes)
            {
                t.SelectedImageIndex = 0;
                t.ImageIndex = 0;
                if (t.Nodes.Count != 0)
                    SetNodeImg11(t);
            }
        }

        //设置节点选定状态:
        //规则.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
        void SetNodeImg12(TreeNode tn)
        {
            if (tn.Parent == null)
                return;
            int Img0Num = 0, Img1Num = 0, Img2Num = 0;
            //统计同级节点选中情况
            foreach (TreeNode t in tn.Parent.Nodes)
            {
                switch (t.ImageIndex)
                {
                    case 1:
                        Img1Num++;
                        break;
                    case 2:
                        Img2Num++;
                        break;
                    case 0:
                    default:
                        Img0Num++;
                        break;
                }
            }
            //如果同级节点选中和未选中的都有
            if (Img1Num != 0 || (Img0Num != 0 && Img2Num != 0))
            {
                tn.Parent.SelectedImageIndex = 1;
                tn.Parent.ImageIndex = 1;
            }
            else
            {
                tn.Parent.StateImageIndex = 0;
                tn.Parent.ImageIndex = 0;
            }
            SetNodeImg12(tn.Parent);
        }

        //设置节点选定状态:
        //规则.1:检查是否有子节点,设置所有子节点为选定状态
        void SetNodeImg21(TreeNode tn)
        {
            foreach (TreeNode t in tn.Nodes)
            {
                t.SelectedImageIndex = 2;
                t.ImageIndex = 2;
                if (t.Nodes.Count != 0)
                {
                    SetNodeImg21(t);
                }
            }
        }

        //设置节点选定状态:
        //规则.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
        void SetNodeImg22(TreeNode tn)
        {
            if (tn.Parent == null)
                return;
            int Img0Num = 0, Img1Num = 0, Img2Num = 0;
            foreach (TreeNode t in tn.Parent.Nodes)
            {
                //if (t.ImageIndex == 0)
                //    Img0Num++;
                //if (t.ImageIndex == 1)
                //    Img1Num++;
                //if (t.ImageIndex == 2)
                //    Img2Num++;
                switch (t.ImageIndex)
                {
                    case 1:
                        Img1Num++;
                        break;
                    case 2:
                        Img2Num++;
                        break;
                    case 0:
                    default:
                        Img0Num++;
                        break;
                }
            }
            if (Img1Num != 0 || (Img0Num != 0 && Img2Num != 0))
            {
                tn.Parent.SelectedImageIndex = 1;
                tn.Parent.ImageIndex = 1;
            }
            //else if (Img1Num == 0 && Img2Num == 0)
            //{
            //    tn.Parent.SelectedImageIndex = 0;
            //    tn.Parent.ImageIndex = 0;
            //}
            else
            {
                tn.Parent.StateImageIndex = 2;
                tn.Parent.ImageIndex = 2;
            }
            SetNodeImg22(tn.Parent);
        }

    }
}
原文地址:https://www.cnblogs.com/z5337/p/3303014.html