今天我在试着做一个C#树形视图(TreeView)控件,要求在每个节点前面添加一个可用于打勾的复选框,并要求复选框有上下级联动的效果。现在在网上能查到挺多满足这类功能的代码,原本我也以为这是一件挺简单的事情,不过实际情况并非如此。

我们建立一个C#窗体应用程序,主窗体取名FormMain,在里面放置一个Dock为Fill的TreeView控件treeTest。注意该控件的CheckBoxes属性要设置为True才能显示复选框。

在FormMain中写入代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace TreeViewCheckTest
{public partial class FormMain : Form{public FormMain(){InitializeComponent();}private void FormMain_Load(object sender, EventArgs e){//生成测试数据TreeNode treeNode11 = new TreeNode("蜉蝣目");treeNode11.Nodes.Add("等蜉科");treeNode11.Nodes.Add("四节蜉科");treeNode11.Nodes.Add("扁蜉科");treeNode11.Nodes.Add("蜉蝣科");treeNode11.Nodes.Add("河花蜉科");TreeNode treeNode12 = new TreeNode("蜚蠊目");treeNode12.Nodes.Add("姬蠊科");treeNode12.Nodes.Add("硕蠊科");treeNode12.Nodes.Add("地鳖科");treeNode12.Nodes.Add("隐尾蠊科");TreeNode treeNode13 = new TreeNode("螳螂目");treeNode13.Nodes.Add("螳科");treeNode13.Nodes.Add("花螳科");treeNode13.Nodes.Add("锥头螳科");treeNode13.Nodes.Add("细足螳科");TreeNode treeNode14 = new TreeNode("其他类型昆虫");TreeNode treeNode1 = new TreeNode("昆虫纲");treeNode1.Nodes.AddRange(new TreeNode[] { treeNode11, treeNode12, treeNode13, treeNode14 });treeTest.Nodes.Add(treeNode1);treeTest.ExpandAll();}/// <summary>/// 关联锁/// </summary>bool needSetRelateCheck = true;/// <summary>/// 树节点前复选框发生变化时触发/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void treeViewEnhanced1_AfterCheck(object sender, TreeViewEventArgs e){if (!needSetRelateCheck){return;}//1、判断当前操作节点勾还是不勾//如果勾,当前节点下所有子节点都要勾上//如果不勾,下面子节点全部不勾TreeNode node = e.Node;if (node.Checked){node.Nodes.OfType<TreeNode>().ToList().ForEach(x => x.Checked = true);}else{node.Nodes.OfType<TreeNode>().ToList().ForEach(x => x.Checked = false);}//2、如果当前节点被勾选,如果当前节点被勾选,则其上溯所有祖先节点都要勾//否则判断当前节点所有兄弟节点是否有勾,有则父节点要勾,没有则父节点不勾needSetRelateCheck = false; //为本方法上锁,确保连带影响不会运行本事件中代码if (node.Checked){while (node.Parent != null){node = node.Parent;node.Checked = true;}}else{while (node.Parent != null){node = node.Parent;bool hasCheckedChild = false;foreach (TreeNode child in node.Nodes){if (child.GetHashCode() == e.Node.GetHashCode()){continue;}if (child.Checked){hasCheckedChild = true;break;}}if (!hasCheckedChild){node.Checked = false;}else{break;}}}needSetRelateCheck = true; //为本方法解锁}}
}

原则上这段代码满足以下功能:

1:勾选一个节点时,该节点的所有子节点都被勾选
2:取消勾选一个节点时,该节点的所有子节点都被取消勾选
3:勾选一个节点时,如果该节点的所有兄弟都被勾选,则该节点的父节点也应被勾选
4:取消勾选一个节点时,如果该节点的所有兄弟节点都未被勾选,则该节点的父节点也应被取消勾选

运行后效果如下:

本来以为这样就好了,结果发生了意想不到的事情:

在我用鼠标点击一个复选框时,如果点击间隔时间过短(达到类似双击的速度),则TreeView的复选框会显示出现无法正确联动的问题。

后来我上网查了一些资料,终于找到了一个大牛给出的原因,参见:

https://social.msdn.microsoft.com/Forums/windows/en-US/9d717ce0-ec6b-4758-a357-6bb55591f956/possible-bug-in-net-treeview-treenode-checked-state-inconsistent?forum=winforms

大牛的答案中说这是一个WindowsVista版本的BUG,不过我现在的32位Win7也会出现此问题。

解决这个问题的方法是将TreeView封装一层,并重写一下WndProc函数:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace TreeViewCheckTest
{/*此种重写此函数,会导致鼠标触发的时候变的缓慢,*/class TreeViewEnhanced : TreeView{protected override void WndProc(ref Message m){if (m.Msg == 0x203) { m.Result = IntPtr.Zero; }else base.WndProc(ref m);}}//改进方法(用此类控件代替将响应变的更快)public class TreeViewEx : TreeView{private const int WM_LBUTTONDBLCLK = 0x0203;private const int WM_RBUTTONDOWN = 0x0204;protected override void WndProc(ref Message m){if (m.Msg == WM_LBUTTONDBLCLK){TreeViewHitTestInfo tvhti = HitTest(new Point((int)m.LParam));if (tvhti != null && tvhti.Location == TreeViewHitTestLocations.StateImage){m.Result = IntPtr.Zero;tvhti.Node.Checked = !tvhti.Node.Checked;return;}}else if (m.Msg == WM_RBUTTONDOWN){TreeViewHitTestInfo tvhti = HitTest(new Point((int)m.LParam));if (tvhti != null)this.SelectedNode = tvhti.Node;}base.WndProc(ref m);}}

实现了TreeViewEnhanced类后,将FormMain中的TreeView控件替换为我们刚刚实现的TreeViewEnhanced就好啦!

转载:https://blog.csdn.net/weixin_34364135/article/details/92548715
转载于:https://my.oschina.net/Tsybius2014/blog/551358

winform中TreeView控件复选框联动时鼠标点击过快导致的显示不正确的问题相关推荐

  1. C# - 解决TreeView控件复选框联动时鼠标点击过快导致的显示不正确的问题

    2019独角兽企业重金招聘Python工程师标准>>> 今天我在试着做一个C#树形视图(TreeView)控件,要求在每个节点前面添加一个可用于打勾的复选框,并要求复选框有上下级联动 ...

  2. 关于怎么获取Repeater控件复选框选中的那一行的数据

    关于怎么获取Repeater控件复选框选中的那一行的数据 1.首先你要有一个repeater控件,并且里面有复选框控件 2.废话不多话,直接上代码 Dim i As Integer'Car是repea ...

  3. Winform中Treeview控件失去焦点,将选择的节点设置为高亮显示 (2012-07-16 13:47:07)转载▼...

    Winform中Treeview控件失去焦点,将选择的节点设置为高亮显示 (2012-07-16 13:47:07)转载▼ 标签: winform treeview drawnode Treeview ...

  4. 5、Web 窗体的基本控件——复选框控件和复选组控件(CheckBox 和 CheckBoxList)

    5.Web 窗体的基本控件--复选框控件和复选组控件(CheckBox 和 CheckBoxList) 复选框控件和复选组控件(CheckBox 和 CheckBoxList) 前端 <%@ P ...

  5. html5 多选框控件,复选框和单选框都属于控件吗

    单选框和复选框的区别是什么? 单选框和复选框的区别是什么? 详细一点-. (1)复选框可以允许你选择多个设置,而单选框则允许你选择一个设置: 这两个选框的区别是一个通过用圆圈表示,一个通过用方框表示. ...

  6. winform中treeview控件实现部分节点显示checkbox

    用过asp.net的应该知道,要在treeview中实现上述功能可以使用ShowCheckBox 属性指定那些节点显示checkbox哪些不显示,可是winform中的treeview只提供一个Sho ...

  7. 在 GridView 控件中添加一列复选框51

    简介 在前面的教程中 , 我们学习了如何为 GridView 控件添加一列 单选 按钮来选择一个特定的记录.当用户被限制最多只能从网格中选中一项时,一列单选按钮是一个非常恰当的用户界面.然而,有时我们 ...

  8. 扩展GridView控件(7) - 行的指定复选框选中时改变行的样式

    GridView既强大又好用.为了让它更强大.更好用,我们来写一个继承自GridView的控件. [索引页] [×××] 扩展GridView控件(7) - 行的指定复选框选中时改变行的样式 作者:w ...

  9. asp.NET中 treeview 控件的使用

    asp.NET中 treeview 控件的使用 treeview控件实现点击Node,弹出相应WebUserControl画面 所需控件 treeview控件 WebUserControl,web用户 ...

最新文章

  1. 高效排序算法(希尔排序)
  2. python中内置函数基本输入输出函数
  3. 江苏省二级c语言考试软件下载,江苏省二级c语言上机考试例题集1-20
  4. Android 解决下拉刷新控件和ScrollVIew的滑动冲突问题。
  5. 从《网管员必读》系列丛书获奖看读者的真正需求——成功原因分析(一)
  6. 跨界合作成潮流 智能家居竞争升级
  7. 原创玄幻小说--那时花开--第一章前序
  8. 符合W3C的网站的开发模型和必要性的探讨(一)
  9. 蚂蚁金服旗下网商银行招聘了
  10. 计算机老是跳出usb设备无法识别,如何解决电脑一直弹出USB设备无法识别的问题?...
  11. java url 收集
  12. 推荐 7 款国产的在线HTML编辑器
  13. Error:Internal error: (java.lang.IllegalArgumentException) Argument for
  14. 思科高级配置(配置标准ACL)
  15. 月薪20K,北漂程序员的真实生活
  16. 网易实习第11天--制作第一个ios应用
  17. 【宝藏】GitHub黑科技的开源项目(有趣高质量)
  18. 【Redis核心知识 八】Redis集群之Cluster模式及集群搭建
  19. Quartz查询所有的定时任务
  20. Latex表格置顶方法

热门文章

  1. 需求跟踪和落地的敏捷实践
  2. 软件测试编号(系统需求跟踪表)
  3. 小程序仿微信写简易聊天室
  4. 基于Android社区养老服务信息平台
  5. linux服务器卡死了,Linux服务器死机的正确处理方法!
  6. PHP判断IP属于国内国外
  7. curl --- post请求参数过长(超过1024B)时请求失败
  8. 使用工具检测你的app:模拟器和真机测试 之一
  9. Unity删除工程记录
  10. Android的java基本知识总结【入门篇】