# DXP TreeList 目錄樹 ## 1.需求背景 需要一個支持`勾選`,`拖動節點`,`保存各節點順序`的目錄樹。  ## ...
DXP TreeList 目錄樹
1.需求背景
需要一個支持勾選
,拖動節點
,保存各節點順序
的目錄樹。
2.創建目錄樹
在treeList
控制項中添加兩個colunm
用來顯示綁定數據
和顯示
值。
接下來對treeList
的屬性進行設置
// 設置列不顯示
treeList.OptionsView.ShowColumns = false;
// 設置序號列不顯示
treeList.OptionsView.ShowIndicator = false;
// 設置垂直線不顯示
treeList.OptionsView.ShowVertLines = false;
// 設置水平線不顯示
treeList.OptionsView.ShowHorzLines = false;
// 設置焦點框為行焦點
treeList.OptionsView.FocusRectStyle = DevExpress.XtraTreeList.DrawFocusRectStyle.RowFocus;
// 隱藏第一列(數據列)
treeListColumn1.Visible = false;
// 設置不可編輯
treeList.OptionsBehavior.Editable = false;
// 設置顯示覆選框
treeList.OptionsView.ShowCheckBoxes = true;
// 設置勾選父節點,子節點自動全選
treeList.OptionsBehavior.AllowRecursiveNodeChecking = true;
添加節點
private TreeListNode AppendNode(PrjTableNode node, int pid)
{
TreeListNode treeListNode = null;
Action<PrjTableNode, int> ac = (arg1, arg2) =>
{
treeListNode = treeList.AppendNode(new object[] { node, node.Alias }, pid, 0, 0, 0);
};
var tt = treeList.Invoke(ac, new object[] { node, pid });
SetNodeCheckState(treeListNode);
return treeListNode;
}
主要用到treeList.AppendNode()
方法,方法定義如下
AppendNode(object nodeData, int parentNodeId, int imageIndex, int selectImageIndex, int stateImageIndex)
- nodeData : object 類型的參數,這裡傳入
object[]
數組對象,數組對應treeList
的列,這裡第一列是數據,第二列用來顯示,因此需要將第一列隱藏。 - parentNodeId :父節點ID
- imageIndex : 節點圖標索引,這裡沒有圖標就給任意一個數字
- selectImageIndex : 節點被選擇後顯示的圖標索引
- stateImageIndex : 狀態圖標索引
此時目錄樹就創建好了。
2.1 設置目錄樹選中節點的背景色
添加CustomDrawNodeCell
事件
// 設置行背景色
treeList.CustomDrawNodeCell -= TreeList_CustomDrawNodeCell;
treeList.CustomDrawNodeCell += TreeList_CustomDrawNodeCell;
設置顏色
private void TreeList_CustomDrawNodeCell(object sender, DevExpress.XtraTreeList.CustomDrawNodeCellEventArgs e)
{
if (e.Node.Selected)
{
e.Appearance.BackColor = Color.FromArgb(192, 192, 255);
}
}
2.2 控制目錄樹節點的勾選框是否顯示
添加CustomDrawNodeCheckBox
事件
// 控制覆選框顯隱
treeList.CustomDrawNodeCheckBox -= TreeList_CustomDrawNodeCheckBox;
treeList.CustomDrawNodeCheckBox += TreeList_CustomDrawNodeCheckBox;
private void TreeList_CustomDrawNodeCheckBox(object sender, DevExpress.XtraTreeList.CustomDrawNodeCheckBoxEventArgs e)
{
// 滿足邏輯條件的 ,將 e.Handled = true 即可
if ((e.Node.GetValue(treeListColumn1) as PrjTableNode)?.Type == ConstClass1.PRJ_TYPE_ID)
{
//e.Handled = true;
}
}
2.3 節點拖拽
這裡的需求是只允許同級節點內部拖動,也不允許拖動到節點子集。
設置屬性OptionsDragAndDrop.DragNodesMode = DragNodesMode.Single
添加DragOver
,DragDrop
,AfterDragNode
事件
// 設置節點拖拽
treeList.OptionsDragAndDrop.DragNodesMode = DragNodesMode.Single;
// 處理拖動時的邏輯
treeList.DragOver -= TreeList_DragOver;
treeList.DragOver += TreeList_DragOver;
// 處理拖動結束時的邏輯
treeList.DragDrop -= TreeList_DragDrop;
treeList.DragDrop += TreeList_DragDrop;
// 處理拖動後的邏輯
treeList.AfterDragNode -= TreeList_AfterDragNode;
treeList.AfterDragNode += TreeList_AfterDragNode;
DragOver 用來處理拖動時的邏輯
當有節點需要禁止拖動時,滿足邏輯時,設置 e.Effect = DragDropEffects.None;
即可
private void TreeList_DragOver(object sender, DragEventArgs e)
{
var currNode = treeList.FocusedNode;
var curNodeData = currNode.GetValue(treeListColumn1) as PrjTableNode;
if (curNodeData == null)
{
return;
}
if (!curNodeData.CanDrag)
{
e.Effect = DragDropEffects.None;
}
}
DragDrop 用來處理拖動結束時的邏輯
private void TreeList_DragDrop(object sender, DragEventArgs e)
{
// 當前節點的父節點變化,則不允許拖動
var dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode;
var sourceParent = dragNode.ParentNode.GetValue(treeListColumn1) as PrjTableNode;
var targetNode = treeList.CalcHitInfo(treeList.PointToClient(MousePosition)).Node;
if (targetNode == null)
{
return;
}
PrjTableNode targetNodeParent = null;
if (targetNode.ParentNode != null)
{
targetNodeParent = targetNode.ParentNode.GetValue(treeListColumn1) as PrjTableNode;
}
// 發生跨級移動
if (sourceParent.Id != targetNodeParent.Id)
{
e.Effect = DragDropEffects.None;
return;
}
// 移到子集
if (AjustDirection(sender, e) == DragInsertPosition.AsChild)
{
e.Effect = DragDropEffects.None;
return;
}
}
/// <summary>
/// 移動過程中的方向
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <returns></returns>
private DragInsertPosition AjustDirection(object sender, DragEventArgs e)
{
var tl = sender as TreeList;
//var dragNode = e.Data.GetData(typeof(TreeListNode)) as TreeListNode;
//var hit = tl.CalcHitInfo(tl.PointToClient(new Point(e.X, e.Y)));
var pi = typeof(TreeList).GetProperty("Handler", BindingFlags.Instance | BindingFlags.NonPublic);
var handler = (TreeListHandler)pi.GetValue(tl, null);
return handler.StateData.DragInfo.DragInsertPosition;
}
AfterDragNode 用來處理拖動結束後的邏輯
private void TreeList_AfterDragNode(object sender, AfterDragNodeEventArgs e)
{
// TODO:...
}
3.總結
treeList
是一個很強大的控制項,用來處理樹狀結構。本次需求中,處理節點拖拽話費了較長時間,也網上找了很多博文,但是都沒有直接解決我的問題,因此在這裡做個筆記。
後記:紙上得來終覺淺,絕知此事要躬行
本文來自博客園,作者:宣君{https://www.nhit.icu/},轉載請註明原文鏈接:https://www.cnblogs.com/ycit/p/17604994.html