做角色菜单权限时用到treeview控件做树状显示菜单,简单总结了一下用法:
1.在winform窗体中拖入treeview控件,注意修改属性CheckBoxes属性为true,即在节点旁显示复选框
2.后台动态加载数据库数据绑定到treeview上,子节点使用递归添加
代码如下:
1 //循环添加treeview节点 2 for (int i = 0; i < dm.Rows.Count - 1; i++)//dm是数据库查出的数据表 3 { 4 //添加父节点(一级菜单) 5 if (int.Parse(dm.Rows[i]["Menu_Type"].ToString()) == 0) 6 { 7 TreeNode pnode = new TreeNode(); 8 pnode.Text = dm.Rows[i]["Menu_Text"].ToString(); 9 pnode.Tag = int.Parse(dm.Rows[i]["Menu_ID"].ToString()); 10 treeView1.Nodes.Add(pnode); 11 //调用方法,添加子级菜单 12 AddChildnode(int.Parse(dm.Rows[i]["Menu_ID"].ToString()), pnode); 13 } 14 }
添加子级菜单的方法如下:
1 public void AddChildnode(int mid, TreeNode pnode) 2 { 3 RoleHandle rh = new RoleHandle(); 4 DataTable dm = rh.Menu_Texts_Type(); 5 6 for (int i = 0; i < dm.Rows.Count - 1; i++) 7 { 8 if (int.Parse(dm.Rows[i]["Menu_Parent"].ToString()) == mid) 9 { 10 TreeNode cnode = new TreeNode(); 11 cnode.Text = dm.Rows[i]["Menu_Text"].ToString(); 12 cnode.Tag = int.Parse(dm.Rows[i]["Menu_ID"].ToString()); 13 pnode.Nodes.Add(cnode); 14 //调用本方法,递归 15 AddChildnode(int.Parse(dm.Rows[i]["Menu_ID"].ToString()), cnode); 16 } 17 } 18 }
3.获取角色对应的权限,有权限则勾选,没有权限则不管
我同样封装了一个方法,方法代码如下:
1 private void RoleChanged() 2 { 3 RoleHandle rh = new RoleHandle(); 4 int roleId = GetSelectedRoleId(); 5 //循环遍历treeview1所有根节点 6 for (int i = 0; i < treeView1.Nodes.Count; i++) 7 { 8 //查询数据库判断是否有该权限 9 if (rh.RoleMenuCheck(int.Parse(treeView1.Nodes[i].Tag.ToString()), roleId) != null && rh.RoleMenuCheck(int.Parse(treeView1.Nodes[i].Tag.ToString()), roleId).Rows.Count > 0) 10 { 11 //如果有权限,则勾选该节点 12 treeView1.Nodes[i].Checked = true; 13 } 14 else 15 { 16 treeView1.Nodes[i].Checked = false; 17 } 18 //调用递归的方法判断其子节点 19 TreeViewAllNodes(treeView1.Nodes[i], roleId); 20 } 21 }
判断子节点菜单是否有权限的方法(即判断子节点是否应勾选)
1 private void TreeViewAllNodes(TreeNode parentNode, int roleId) 2 { 3 RoleHandle rh = new RoleHandle(); 4 foreach (TreeNode node in parentNode.Nodes) 5 { 6 if (rh.RoleMenuCheck(int.Parse(node.Tag.ToString()), roleId) != null && rh.RoleMenuCheck(int.Parse(node.Tag.ToString()), roleId).Rows.Count > 0) 7 { 8 node.Checked = true; 9 } 10 else 11 { 12 node.Checked = false; 13 } 14 if (node.Nodes.Count > 0)//如果该节点下还有子节点 15 { 16 //运用递归,调用改方法 17 TreeViewAllNodes(node, roleId); 18 } 19 } 20 }
4.使用鼠标单击treeview节点事件,实现点击某treeview节点时的子节点和父节点联动,代码如下:
1 private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) 2 { 3 //判断该节点状态(展开或折叠) 4 if (nodestate) 5 { 6 TreeNode node = e.Node; 7 if (node.Nodes.Count > 0)//包含子节点,实现子级联动 8 { 9 //实现子级联动的方法 10 SetTreeViewChecked(node); 11 } 12 if (node.Parent != null)//有父级菜单,实现父级联动 13 { 14 //实现父级联动的方法 15 SetParentNodeState(node); 16 } 17 nodestate = false;//修改节点状态 18 } 19 }
子级联动的方法如下:
1 private void SetTreeViewChecked(TreeNode node) 2 { 3 if (node == null) 4 { 5 return; 6 } 7 if (node.Nodes.Count > 0)//判断该节点下有子节点 8 { 9 foreach (TreeNode item in node.Nodes) 10 { 11 item.Checked = node.Checked; 12 //调用该方法,递归 13 SetTreeViewChecked(item); 14 } 15 } 16 }
父级联动方法如下:
1 private void SetParentNodeState(TreeNode node) 2 { 3 //定义变量用来设置父节点的选中情况,bool ck = false;假设子节点为全不选情况 4 bool ck = false; 5 TreeNode pn = node.Parent; 6 if (pn != null) 7 { 8 //假设所有子节点为全未选,循环判断是否有子节点选中 9 foreach (TreeNode item in pn.Nodes) 10 { 11 //如果有一个子节点是选中的,ck=true; 12 if (item.Checked) 13 { 14 ck = true; 15 break; 16 } 17 } 18 if (ck) 19 { 20 pn.Checked = true; 21 } 22 else 23 { 24 pn.Checked = false; 25 SetParentNodeState(pn);//递归 26 } 27 } 28 }
补充说明一下,鼠标单击treeview节点事件有点坑,折叠或展开节点时也会触发该事件,所以我使用了TreeView1_AfterCheck事件解决了这个问题
1 //设置全局变量,用来接收节点的状态 2 private bool nodestate = false; 3 private void RoleMenuForm_Load(object sender, EventArgs e) 4 { 5 //在窗体加载事件中注册方法treeView1.AfterCheck 6 treeView1.AfterCheck += TreeView1_AfterCheck; 7 } 8 //treeView1.AfterCheck方法 9 10 private void TreeView1_AfterCheck(object sender, TreeViewEventArgs e) 11 { 12 //改变节点状态 13 nodestate = true; 14 }