本文核心部分采用 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); } } }