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); } }
效果如下圖所示: