WinForm TreeView的一点用法
TreeView一般都包含父节点和子节点,常规情况下有以下几种情况:
1.选中父节点之后,该父节点下面的所有子节点都被选中,取消选择父节点,则该父节点下面所有的子节点全部跟着取消选择。
2.如果某一个父节点下面有任何一个子节点被选中,那么该父节点也是处于选中状态。
3.如果某一个父节点下面最后一个处于选中的子节点被取消选中的话(这句话貌似有点绕口),该父节点也要处于取消选中的状态。
4.页面首先将所有的数据加载到TreeView上面,然后TreeView根据不同的情况做出相应的调整,比如选择Admin组别的时候勾选所有的选项,勾选User组别的时候仅仅勾选允许登录的选项。
前面3种情况可以如下解决:
private bool m_SetClick = true; private void SetSubNodeCheck(TreeNode p_TreeNode, bool p_SelectCheck) { m_SetClick = false; foreach (TreeNode _SubNode in p_TreeNode.Nodes) { _SubNode.Checked = p_SelectCheck; SetSubNodeCheck(_SubNode, p_SelectCheck); } } private void SetParentCheck(TreeNode p_TreeNode) { if (p_TreeNode.Checked && p_TreeNode.Parent != null) { p_TreeNode.Parent.Checked = true; SetParentCheck(p_TreeNode.Parent); } } private void SetParentNotCheck(TreeNode p_TreeNode) { if (!p_TreeNode.Checked && p_TreeNode.Parent != null) { foreach (TreeNode _Node in p_TreeNode.Parent.Nodes) { if (_Node.Checked) return; } p_TreeNode.Parent.Checked = false; SetParentNotCheck(p_TreeNode.Parent); } }
然后在AfterCheck里面增加如下代码:
private void tvFunction_AfterCheck(object sender, TreeViewEventArgs e) { // 禁用TreeView视图重绘的功能。 tvFunction.BeginUpdate(); if (m_SetClick) { SetSubNodeCheck(e.Node, e.Node.Checked); SetParentCheck(e.Node); SetParentNotCheck(e.Node); m_SetClick = true; } // 启用TreeView视图重绘的功能。 tvFunction.EndUpdate(); }
关于第4个问题,我遇到的情况是这样的,在权限设置里面我想在窗体Load的时候将所有的菜单组以及对应的子菜单都加载到树上面来,当我点击不同的角色的时候自动显示对应的权限,比如,我点击Administrator”,则TreeView上面的所有菜单组以及子菜单全部都勾选上,如果我点击“普通用户”,则那些系统设置相关的内容都不勾选,这就是需求,下面我们来看看如何实现这个需求:
首先,我根据不同的角色返回了一张表或者是一个集合,当用户点击角色名称的时候就已经获取到了这个表或者集合,我们要做的就是匹配界面上面TreeView里面的所有节点和返回来的那一张Table或者集合,如果能够完全匹配,那么就将其Checked属性设置为True,否则不理它,这里用到了递归来遍历这棵树,递归代码如下:
/// <summary> /// 递归遍历TreeView,然后对比已有的数据和TreeView上面的节点数据, /// 如果匹配成功,则选中TreeView上面的相应节点。 /// </summary> /// <param name="tn"></param> private void FindTreeView(TreeNode tn) { tn.Checked = false; string FunctionID_dt = string.Empty; string FunctionID_tv = string.Empty; for (int i = 0; i < dt_ExistsRole.Rows.Count; i++) { FunctionID_dt = dt_ExistsRole.Rows[i][1].ToString().Trim(); FunctionID_tv = tn.Name.Trim(); if (FunctionID_dt == FunctionID_tv) { tn.Checked = true; } } foreach (TreeNode tnSub in tn.Nodes) { FindTreeView(tnSub); } }
在TreeView的AfterSelect事件里面调用它,一定要是AfterSelect里面,而不是Click里面:
private void tvUserGroup_AfterSelect(object sender, TreeViewEventArgs e) { //每次选择一个节点的时候都取到这个节点的名称,名称就是数据库里面的UserGroupID。 dt_ExistsRole = new BLL.sys_SetRoleManager().GetExistsRole("1", tvUserGroup.SelectedNode.Name); foreach (TreeNode tn in tvFunction.Nodes) { FindTreeView(tn); } }
效果如下图所示:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?