首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# TreeView 節點拖曳移動與複製完整實作

     編輯:關於C語言

核心事件與屬性

實作 TreeView 節點拖放需設定 AllowDrop = true 並處理四大事件:

  • ItemDrag:啟動拖放作業(DoDragDrop)
  • DragEnter:設定允許的放置效果
  • DragOver:即時反饋目標節點(高亮選中)
  • DragDrop:完成移動/複製邏輯

完整程式碼


public class Form4 : Form {
    private TreeView treeView1;

    public Form4() {
        treeView1 = new TreeView();
        treeView1.AllowDrop = true;
        treeView1.Dock = DockStyle.Fill;

        // 建立測試節點
        for (int x = 0; x < 3; x++) {
            TreeNode root = treeView1.Nodes.Add($"Node{x * 4}");
            for (int y = 1; y < 4; y++) root.Nodes.Add($"Node{x * 4 + y}");
        }

        // 事件繫結
        treeView1.ItemDrag += TreeView1_ItemDrag;
        treeView1.DragEnter += TreeView1_DragEnter;
        treeView1.DragOver += TreeView1_DragOver;
        treeView1.DragDrop += TreeView1_DragDrop;

        this.ClientSize = new Size(292, 273);
        this.Controls.Add(treeView1);
    }

    // 1. 啟動拖放:左鍵=移動,右鍵=複製
    private void TreeView1_ItemDrag(object sender, ItemDragEventArgs e) {
        if (e.Button == MouseButtons.Left)
            DoDragDrop(e.Item, DragDropEffects.Move);
        else if (e.Button == MouseButtons.Right)
            DoDragDrop(e.Item, DragDropEffects.Copy);
    }

    // 2. 進入控制項:接受來源允許的效果
    private void TreeView1_DragEnter(object sender, DragEventArgs e) {
        e.Effect = e.AllowedEffect;
    }

    // 3. 拖曳中:高亮目標節點
    private void TreeView1_DragOver(object sender, DragEventArgs e) {
        Point pt = treeView1.PointToClient(new Point(e.X, e.Y));
        treeView1.SelectedNode = treeView1.GetNodeAt(pt);
    }

    // 4. 放置:執行移動/複製,防止父子循環
    private void TreeView1_DragDrop(object sender, DragEventArgs e) {
        Point pt = treeView1.PointToClient(new Point(e.X, e.Y));
        TreeNode target = treeView1.GetNodeAt(pt);
        TreeNode dragged = (TreeNode)e.Data.GetData(typeof(TreeNode));

        if (dragged == null || target == null) return;
        if (dragged.Equals(target) || ContainsNode(dragged, target)) return; // 避免移至自己或子孫

        if (e.Effect == DragDropEffects.Move) {
            dragged.Remove();
            target.Nodes.Add(dragged);
        } else if (e.Effect == DragDropEffects.Copy) {
            target.Nodes.Add((TreeNode)dragged.Clone());
        }
        target.Expand();
    }

    // 遞迴檢查 node1 是否為 node2 的祖先
    private bool ContainsNode(TreeNode node1, TreeNode node2) {
        if (node2.Parent == null) return false;
        if (node2.Parent.Equals(node1)) return true;
        return ContainsNode(node1, node2.Parent);
    }
}

關鍵細節解析

  • DoDragDrop 參數:`e.Item` 為被拖曳的 `TreeNode` 物件,第二參數指定允許效果(Move/Copy)。
  • 座標轉換:`DragEventArgs.X/Y` 為螢幕座標,必須用 `PointToClient` 轉為控制項座標,再呼叫 `GetNodeAt` 取得節點。
  • 防循環邏輯:`ContainsNode` 遞迴檢查,防止將父節點拖入自身子樹造成無限巢狀。
  • Clone():複製模式下需呼叫 `Clone()` 建立獨立節點實例,否則會移動原節點。

進階擴充建議

  • 加入 DragLeave 清除高亮選取。
  • 支援多選節點拖放(需自行維護選取集合)。
  • 搭配 `ContextMenuStrip` 實現右鍵選單輔助操作。
  • 大量節點時考慮虛擬模式或延遲載入子節點。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved