三状态 TreeView 扩展

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;

namespace UtilityClass
{
    public class TreeViewEx : TreeView
    {
        private ImageList imageList1;
        private System.ComponentModel.IContainer components;
        [DefaultValue(false), Browsable(false)]
        public new bool CheckBoxes { get; private set; }
        private int imageWidth = 0x12 + 2;  // 图片大小加空隙

        //private bool isFirstDifferent = true;
        //[DefaultValue(true), Description("将第一个节点作为全选/全不选。")]
        //public bool IsFirstDifferent //{ get; set; }
        //{
        //    get
        //    {
        //        return isFirstDifferent;
        //    }
        //    set
        //    {
        //        if (isFirstDifferent != value)
        //            isFirstDifferent = value;
        //    }
        //}

        public TreeViewEx()
        {
            InitializeComponent();
            // 防止图片过大
            //imageWidth = imageList1.ImageSize.Width + 2;
        }

        //规则1:取消选定
        //规则1.1:检查是否有子节点,需清除所有子节点的选定状态;
        //规则1.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
        //规则2:选定
        //规则2.1:检查是否有子节点,设置所有子节点为选定状态
        //规则2.2:检查是否有父节点,如有,则根据兄弟节点的选定状态修改父节点的选定状态
        private void TreeViewEx_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 (IsFirstDifferent && e.Node.Level == 0 && e.Node.Index == 0)
                    if (e.Node.Level == 0 && e.Node.Index == 0)
                    {
                        if (e.Node.ImageIndex > 0)
                            NodeUnSelected();
                        else
                            NodeSelected();
                    }
                    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>
        /// 返回指定节点选中状态
        /// 有三种状态 Unchecked 未选中 Indeterminate 部分选中 Checked 选中
        /// </summary>
        /// <param name="tn">节点是否被选中</param>
        /// <returns>返回选中状态信息</returns>
        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>
        /// 半选与全选返回 true 否则返回 false
        /// </summary>
        public bool IsChecked(TreeNode tn)
        {
            return tn.ImageIndex > 0;
        }

        /// <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;

            bool select = true;
            bool unselect = true;
            foreach (TreeNode t in tn.Parent.Nodes)
            {
                if (t.ImageIndex > 0)
                    unselect = false;
                if (t.ImageIndex < 2)
                    select = false;
            }
            if (select)
            {
                tn.Parent.SelectedImageIndex = 2;
                tn.Parent.ImageIndex = 2;
            }
            else if (unselect)
            {
                tn.Parent.SelectedImageIndex = 0;
                tn.Parent.ImageIndex = 0;
            }
            else
            {
                tn.Parent.SelectedImageIndex = 1;
                tn.Parent.ImageIndex = 1;
            }
            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;
            bool select = true;
            bool unselect = true;
            foreach (TreeNode t in tn.Parent.Nodes)
            {
                if (t.ImageIndex > 0)
                    unselect = false;
                if (t.ImageIndex < 2)
                    select = false;
            }
            if (select)
            {
                tn.Parent.SelectedImageIndex = 2;
                tn.Parent.ImageIndex = 2;
            }
            else if (unselect)
            {
                tn.Parent.SelectedImageIndex = 0;
                tn.Parent.ImageIndex = 0;
            }
            else
            {
                tn.Parent.SelectedImageIndex = 1;
                tn.Parent.ImageIndex = 1;
            }
            SetNodeImg22(tn.Parent);
        }

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TreeViewEx));
            this.imageList1 = new System.Windows.Forms.ImageList(this.components);
            this.SuspendLayout();
            // 
            // imageList1
            // 
            this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream")));
            this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
            this.imageList1.Images.SetKeyName(0, "CHECKBOX_NONE.png");
            this.imageList1.Images.SetKeyName(1, "CHECKBOX_HALF.png");
            this.imageList1.Images.SetKeyName(2, "CHECKBOX_ALL.png");
            // 
            // TreeViewEx
            // 
            this.ImageIndex = 0;
            this.ImageList = this.imageList1;
            this.LineColor = System.Drawing.Color.Black;
            this.SelectedImageIndex = 0;
            this.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.TreeViewEx_NodeMouseClick);
            this.ResumeLayout(false);
        }
    }
}

 

posted on 2014-04-22 21:34  z5337  阅读(181)  评论(0)    收藏  举报