c# 项目中需要实现树状选项的勾选,有全选,半勾选,不选的状态。
因原控件中只有勾选和不勾选两种状态,所以半勾选状态需要使用代码绘制和自行定义。
勾选:Node.Checked=true
不勾选: Node.Checked=false
半勾选: Node.Checked=false && Node.ToolTipText="部分勾选"
注意:半勾选状态需要重新绘制控件需要设置控件属性DrawMode为OwnerDrawText或者OwnerDrawAll
核心逻辑一:设置父亲节点的选中状态(选中一个节点时,判断兄弟节点是否全选;取消一个节点时,需要判断兄弟节点是否有选中状态和半选中状态。由此来判断父节点的选中状态)
//取消节点选中状态之后,取消所有父节点的选中状态 private void setParentNodeCheckedState(TreeNode currNode, bool state) { TreeNode parentNode = currNode.Parent; //获得当前节点的父节点 parentNode.Checked = state; //设置父节点的选中状态 if (state == false) //当状态设置为false { int flag = 0; foreach (TreeNode broNode in parentNode.Nodes) //判断该父节点的子节点中,是否有半勾选状态的选项 { if (broNode.Checked||broNode.ToolTipText.Equals("部分勾选")) { flag = 1; } } if (flag == 1) // 有设置父节点为半勾选状态 { parentNode.ToolTipText = "部分勾选"; parentNode.Checked = false; } else { //设置父节点状态为 未勾选 parentNode.ToolTipText = ""; parentNode.Checked = true; parentNode.Checked = false; //需要改变节点的Checked状态,才能重新绘制控件; } } else { //当父节点设置为选中状态时 int flag = 0; foreach (TreeNode broNode in parentNode.Nodes)//判断该父节点的子节点下是否有未选中的节点。 { if (!broNode.Checked) { flag = 1; } } if (flag == 1) { parentNode.ToolTipText = "部分勾选"; parentNode.Checked = false; } else { parentNode.ToolTipText = ""; parentNode.Checked = true; } } if (currNode.Parent.Parent != null) //如果父节点之上还有父节点 { setParentNodeCheckedState(currNode.Parent, state); //递归调用 } }
核心逻辑二:设置子节点的选中状态
//选中节点之后,选中节点的所有子节点 private void setChildNodeCheckedState(TreeNode currNode, bool state) { TreeNodeCollection nodes = currNode.Nodes; //获取所有子节点 if (nodes.Count > 0) //存在子节点 foreach (TreeNode tn in nodes) { tn.Checked = state; tn.ToolTipText = ""; setChildNodeCheckedState(tn, state);//递归调用子节点的子节点 } }
设置控件监听属性AfterCheck
private void skinTreeView1_AfterCheck(object sender, TreeViewEventArgs e) { if (e.Action == TreeViewAction.ByMouse) //鼠标点击 { //textBox1.Text = e.Node.Text; if (e.Node.Checked) //选中 { e.Node.ToolTipText = ""; //选中节点之后,选中节点的所有子节点 setChildNodeCheckedState(e.Node, true); if (e.Node.Parent != null) { setParentNodeCheckedState(e.Node, true); } } else //取消选中 { e.Node.ToolTipText = ""; //取消节点选中状态之后,取消所有子节点的选中状态 setChildNodeCheckedState(e.Node, false); //如果节点存在父节点,取消父节点的选中状态 if (e.Node.Parent != null) { setParentNodeCheckedState(e.Node, false); } } } }
设置重新绘制监听DrawNode,为半勾选状态绘制新图案
private void ClassTreeList_DrawNode(object sender, DrawTreeNodeEventArgs e) { if (e.Bounds.Location.X <= 0) { return; } var treeview = sender as TreeView; var brush = Brushes.Black; //黑色 if (e.Node.ToolTipText.EndsWith("部分勾选")&&e.Node.Checked==false) { //判断为半勾选状态 var location = e.Node.Bounds.Location; location.Offset(-10, 7); var size = new Size(7, 7); e.Graphics.FillRectangle(brush, new Rectangle(location, size)); //这里绘制的是正方形 } //绘制文本 e.Graphics.DrawString(e.Node.Text, treeview.Font, brush, e.Bounds.Left, e.Bounds.Top); }