做爲一個C#程序員,在寫程序時一直以來都使用的微軟那一套控件,用起來特別爽,但是最近公司的一個項目用到了DevExpress框架,不用不知道,一用嚇一跳,不得不認可這個框架確實很強大,效果也很炫,可是用這個框架也遇到了不少讓我頭疼的問題,因爲該控件可能使用的人少,在網上能查到的解決辦法實在有限,因此在解決問題時效率低得讓我有些接受不了,因此再此把我遇到的一些問題和解決思路以及解決結果給你們分享一下,該篇博文只針對DevExpress.XtraTreeList.TreeList 樹形控件來講如下簡稱(Dev樹形),let's do it\(≧▽≦)/:node
首先羅列出所需功能:程序員
一、樹形的綁定(給數據源對樹形進行綁定)數據庫
二、樹形節點的查找(根據用戶輸入的名字進行模糊查詢節點數據:重點在於根據子節點反向遞歸父節點) 框架
三、樹形的右鍵選中節點(在節點上點擊右鍵時就選中節點)this
四、根據ID選中節點(該功能着實讓我頭疼了很久)編碼
依次展現出這幾個功能的效果圖:spa
樹形的綁定:3d
因爲 Dev樹形 在樹形綁定時須要特定格式,那麼咱們先來展現出 Dev樹形 所要使用到的實體類代碼:調試
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace BW.PropertyModel.Class { public class TreeListModel { #region 字段屬性 private int id; /// <summary> /// 節點編號 /// </summary> public int ID { get { return id; } set { id = value; } } private int parentID; /// <summary> /// 父節點編號 /// </summary> /// <value>The parent ID.</value> public int ParentID { get { return parentID; } set { parentID = value; } } private string menuName; /// <summary> /// 菜單名稱 /// </summary> public string MenuName { get { return menuName; } set { menuName = value; } } private object tag; /// <summary> /// 用於裝節點對象 /// </summary> public object Tag { get { return tag; } set { tag = value; } } #endregion } }
解釋一下這四個字段的用途:ID 是獨一無二的,在樹形綁定時可使用數據庫中你要綁定的那個對象的ID;ParentID用於 Dev樹形 識別節點所屬關係(也就是該節點屬哪一個節點);MenuName 用於 Dev樹形 節點的顯示名; Tag用於裝你所須要的任意對象orm
接下來再附圖給你們展現給 Dev樹形 綁定這幾個字段,第二張圖是接着第一張未展現完的地方,這8個地方我就不一一解釋了,本身下來仔細看看,他們的含義一目瞭然的,這裏須要注意的一點是:visible這個屬性;接下來講一說數據源的事:數據源要根據數據庫中的數據進行遞歸處理,附上遞歸處理和初始化樹形的代碼:
/// <summary> /// 加載設備樹形 /// </summary> public void InitFacilityTree() { List<TreeListModel> list = new List<TreeListModel>(); int systemId = 0; if (this.cmbSystemClassify.EditValue != null) { int.TryParse(this.cmbSystemClassify.EditValue.ToString(), out systemId); } List<BW.DMSystem.Core.Entity.ModelManageInfo> temp = BLLFactory<BW.DMSystem.Core.BLL.ModelManage>.Instance.GetAll(string.Format("where IsGallery = 0 and SystemID = {0} order by ID asc", systemId)); //查詢數據庫中某個系統的數據 TreeList(0, ref list, temp); //這裏傳的0表示 根節點 this.tvFacilityModel.KeyFieldName = "ID"; //這裏綁定的ID的值必須是獨一無二的 this.tvFacilityModel.ParentFieldName = "ParentID"; //表示使用parentID進行樹形綁定 this.tvFacilityModel.DataSource = list; //綁定數據源 this.tvFacilityModel.ExpandAll(); //默認展開全部節點 } /// <summary> /// 遞歸調用——正向生成樹形所需結構 /// </summary> /// <param name="parentId">根節點的父編碼默認爲0</param> /// <param name="listData">樹形綁定的數據集合</param> /// <param name="modelList">某系統的結構數據</param> private void TreeList(int parentId, ref List<TreeListModel> listData, List<BW.DMSystem.Core.Entity.ModelManageInfo> modelList) { List<BW.DMSystem.Core.Entity.ModelManageInfo> tmp = modelList.Where(model => model.ParentCode == parentId).ToList(); //這句話很重要,對數據進行篩選全靠它 foreach (var item in tmp) { TreeListModel temp = new TreeListModel(); temp.ID = item.ID; temp.MenuName = item.Name; temp.ParentID = parentId; temp.Tag = item; listData.Add(temp); TreeList(item.ID, ref listData, modelList); } }
我這裏使用的樹形是根據系統分了類的,你若是不須要能夠無論 根據註釋應該能猜出個大概 樹形的綁定就算告一段落了
樹形節點的查找:
效果圖是最開始的第二張圖
代碼:
/// <summary> /// 搜索事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSearch_Click(object sender, EventArgs e) { List<TreeListModel> list = new List<TreeListModel>(); List<int> listId = new List<int>(); //這個集合用於存儲已經加入了的父節點ID,由於有些子節點可能同在一個父節點下若重複插入同ID的數據會報錯 string inputStr = this.txtModelName.Text.Trim(); string systemId = string.Empty; if (this.cmbSystemClassify.EditValue != null) { systemId = this.cmbSystemClassify.EditValue.ToString(); } else { systemId = "0"; } if (string.IsNullOrEmpty(inputStr)) { //若是爲空則查詢全部 List<BW.DMSystem.Core.Entity.ModelManageInfo> temp = BLLFactory<BW.DMSystem.Core.BLL.ModelManage>.Instance.GetAll(string.Format("where IsGallery = 0 and SystemID = '{0}' order by ID asc", systemId)); TreeList(0, ref list, temp); } else { //查詢出全部數據 List<BW.DMSystem.Core.Entity.ModelManageInfo> allData = BLLFactory<BW.DMSystem.Core.BLL.ModelManage>.Instance.GetAll(string.Format("where IsGallery = 0 and SystemID = '{0}' order by ID asc", systemId)); //查詢出知足條件的 List<BW.DMSystem.Core.Entity.ModelManageInfo> temp = BLLFactory<BW.DMSystem.Core.BLL.ModelManage>.Instance.GetAll(string.Format("where IsGallery = 0 and IsModel = 1 and SystemID = '{0}' and Name like '%{1}%' order by ID asc", systemId, inputStr)); for (int i = 0; i < temp.Count; i++) { TreeListModel currNode = new TreeListModel(); currNode.ID = temp[i].ID; currNode.MenuName = temp[i].Name; currNode.ParentID = temp[i].ParentCode; currNode.Tag = temp[i]; list.Add(currNode); listId.Add(temp[i].ID); TreeList_fanxiang(temp[i].ParentCode, ref list, ref listId, allData); } } this.tvFacilityModel.KeyFieldName = "ID"; this.tvFacilityModel.ParentFieldName = "ParentID"; this.tvFacilityModel.DataSource = list; this.tvFacilityModel.ExpandAll(); } }
/// <summary> /// 遞歸調用——反向查找節點的根節點 /// </summary> /// <param name="currId">根節點的父編碼默認爲0</param> /// <param name="listData">樹形綁定的數據集合</param> /// <param name="modelList">某系統的結構數據</param> private void TreeList_fanxiang(int parentId, ref List<TreeListModel> listData, ref List<int> listId, List<BW.DMSystem.Core.Entity.ModelManageInfo> modelList) { List<BW.DMSystem.Core.Entity.ModelManageInfo> tmp = modelList.Where(model => model.ID == parentId).ToList(); //正向和反向的最終區別就在於這句話 foreach (var item in tmp) { TreeListModel temp = new TreeListModel(); temp.ID = item.ID; temp.MenuName = item.Name; temp.ParentID = item.ParentCode; temp.Tag = item; if (!listId.Contains(item.ID)) { listData.Add(temp); listId.Add(item.ID); } TreeList_fanxiang(item.ParentCode, ref listData, ref listId, modelList); } }
根據註釋理解代碼的含義,節點查找也告一段落了。
樹形節點的右鍵選中:
在節點上鼠標右鍵點擊時默認是不會選中該節點的,這個功能說簡單不簡單說複雜也不復雜,我就直接附上代碼來
/// <summary> /// 鼠標右鍵事件 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void tvFacilityModel_MouseUp(object sender, MouseEventArgs e) 須要注意的是 這個事件不要搞錯了 { DevExpress.XtraTreeList.TreeList tree = sender as DevExpress.XtraTreeList.TreeList; if ((e.Button == MouseButtons.Right) && (ModifierKeys == Keys.None) && (tvFacilityModel.State == TreeListState.Regular)) //這裏的幾個條件只有第一個條件有點用,其餘的無關緊要 { Point p = new Point(Cursor.Position.X, Cursor.Position.Y); //獲取到鼠標點擊的座標位置 TreeListHitInfo hitInfo = tree.CalcHitInfo(e.Location); if (hitInfo.HitInfoType == HitInfoType.Cell) { tree.SetFocusedNode(hitInfo.Node); //這句話就是關鍵,用於選中節點 TreeListNode selectNode = this.tvFacilityModel.FocusedNode; BW.DMSystem.Core.Entity.ModelManageInfo modelObj = selectNode.GetValue(3) as BW.DMSystem.Core.Entity.ModelManageInfo; if (modelObj == null) { return; } if (modelObj.IsModel) { this.ModelID = modelObj.ID.ToString(); this.ModelName = modelObj.Name; popupMenu1.ShowPopup(p); } } } }
再來看看微軟的右鍵選中節點的代碼:
private void treeView1_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { treeView1.SelectedNode = treeView1.GetNodeAt(e.X, e.Y);
} }
誒,有種說不出的悲傷。。。OK該功能已Over
根據ID選中節點:
這裏的思路起始很簡單,只要找出樹形中已經綁定的數據源中某個節點的ID的值和傳遞過來的值同樣就選中就好了,可是就是這樣一個簡單的思路 Dev樹形 卻搞了不少花樣着實讓我蛋疼不已啊,本來想直接遍歷樹形的節點的,可是調試中發現 this.tvFacilityModel.Nodes.Count 這句話竟然返回的只有第一級的節點,那怎麼辦呢?——又只有用遞歸查找了澀 誒,附上遞歸查找代碼:
/// <summary> /// 遞歸查找子節點 /// </summary> /// <param name="node"></param> /// <param name="ID"></param> /// <returns></returns> private TreeListNode nodes(TreeListNode node, string ID) { TreeListNode returnNodex = null; if (node.HasChildren) { for (int i = 0; i < node.Nodes.Count; i++) { if (node.Nodes[i].GetValue("ID").ToString() == ID) { returnNodex = node.Nodes[i]; break; } else { returnNodex = nodes(node.Nodes[i], ID); } } } return returnNodex; }
最後再使用 this.tvFacilityModel.FocusedNode = selectNode; 將返回來的節點設置給 Dev樹形 就OK了。
通過此次對樹形控件的使用,沒有多大的收穫,收穫最大的就是對遞歸這種方式有了更深的認識,也熟練了很多,Dev樹形控件個人痛啊!~~~~(>_<)~~~~
好了,也許個人代碼不夠精簡,目前的技術也就寫的出這樣的代碼,但願廣大朋友不要介意,有什麼意見和須要幫助請進行評論或留言,多多溝通有助於發展。