C# WinForms - 在同一 TreeViewControl 中拖放

Posted

技术标签:

【中文标题】C# WinForms - 在同一 TreeViewControl 中拖放【英文标题】:C# WinForms - DragDrop within the same TreeViewControl 【发布时间】:2014-01-21 19:23:54 【问题描述】:

我正在尝试在同一控件中实现树视图项的 DragDrop。

我希望能够将一个项目从一个节点移动到另一个节点。

这是我当前的代码,当我运行它时,我可以看到项目已开始拖动,但窗口图标不允许将其拖放到控件上的任何节点。

我当前的代码

private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)

    DoDragDrop(e.Item, DragDropEffects.Move);


private void treeView1_DragEnter(object sender, DragEventArgs e)

    e.Effect = DragDropEffects.Move;


private void treeView1_DragDrop(object sender, DragEventArgs e)

    if (e.Data.GetDataPresent(typeof(TreeNode)))
    
        TreeNode sourceNode = e.Data.GetData(typeof(TreeView)) as TreeNode;

        var item = new TreeNode(sourceNode.Text);


        System.Drawing.Point pt = ((TreeView)sender).PointToClient(new System.Drawing.Point(e.X, e.Y));
        TreeNode DestinationNode = ((TreeView)sender).GetNodeAt(pt);

        DestinationNode.Nodes.Add(item);
        DestinationNode.Expand();
    

【问题讨论】:

【参考方案1】:

只需将treeView1_DragDrop函数修改为:

private void treeView1_DragDrop(object sender, DragEventArgs e)

    // Retrieve the client coordinates of the drop location.
    Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));

    // Retrieve the node at the drop location.
    TreeNode targetNode = treeView1.GetNodeAt(targetPoint);

    // Retrieve the node that was dragged.
    TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode));

    // Confirm that the node at the drop location is not 
    // the dragged node and that target node isn't null
    // (for example if you drag outside the control)
    if (!draggedNode.Equals(targetNode) && targetNode != null)
    
        // Remove the node from its current 
        // location and add it to the node at the drop location.
        draggedNode.Remove();
        targetNode.Nodes.Add(draggedNode);

        // Expand the node at the location 
        // to show the dropped node.
        targetNode.Expand();
    

【讨论】:

我知道@Francesco B. 正在解决这个人的特定问题,但我想我会添加,在函数顶部插入以下行“TreeView treeView1 = (TreeView) sender;”它变成更可重复使用。 请注意,如果您已经创建了自己的 TreeNode 类,则必须在调用 e.Data.GetData 时使用该类型名称,否则 draggedNode 将变为 null。【参考方案2】:

在树控件上设置AllowDrop=true

【讨论】:

必须修复我的回复,我确实忘记设置 AllowDrop 但它仍然无法正常工作:( - 我正在做一些调整,可能很快会更新我的帖子【参考方案3】:

略微改进的版本,可防止您将节点放到自身或其任何后代上

private void treeView1_DragDrop(object sender, DragEventArgs e)

    TreeNode draggedNode = (MatfloNode)drgevent.Data.GetData(typeof(TreeNode));

    Point pt = this.PointToClient(new System.Drawing.Point(drgevent.X, drgevent.Y));
    TreeNode targetNode = this.GetNodeAt(pt);

    TreeNode parentNode = targetNode;

    if (draggedNode != null &&
        targetNode != null  )
    
        bool canDrop = true;
        while (canDrop && (parentNode != null))
        
            canDrop = !Object.ReferenceEquals(draggedNode, parentNode);
            parentNode = parentNode.Parent;
        

        if (canDrop)
        
            draggedNode.Remove();
            targetNode.Nodes.Add(draggedNode);
            targetNode.Expand();
        
    

【讨论】:

【参考方案4】:

对 DragDrop 处理程序进行了一些改进和添加,以配合所有其他修订。

添加支持:

支持将节点拖放到树视图背景上(底部)。节点被添加到树的底部。 合并了 mrpurple 的“不要放在子节点上”示例并对其进行了修饰,使其与原始示例一致。 还这样做了,以便在拖放节点后选中它。建议在此处也加载已删除节点的内容,否则 用户可能会对当前显示的内容与选择的节点感到困惑。

注意:请务必在树视图控件上设置 AllowDrop=true,否则无法删除节点。

private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)

    DoDragDrop(e.Item, DragDropEffects.Move);


private void treeView1_DragEnter(object sender, DragEventArgs e)

    e.Effect = DragDropEffects.Move;


private void treeView1_DragDrop(object sender, DragEventArgs e)

    // Retrieve the client coordinates of the drop location.
    Point targetPoint = treeView1.PointToClient(new Point(e.X, e.Y));

    // Retrieve the node at the drop location.
    TreeNode targetNode = treeView1.GetNodeAt(targetPoint);

    // Retrieve the node that was dragged.
    TreeNode draggedNode = e.Data.GetData(typeof(TreeNode));

    // Sanity check
    if (draggedNode == null)
    
        return;
    

    // Did the user drop on a valid target node?
    if (targetNode == null)
    
        // The user dropped the node on the treeview control instead
        // of another node so lets place the node at the bottom of the tree.
        draggedNode.Remove();
        treeView1.Nodes.Add(draggedNode);
        draggedNode.Expand();
    
    else
    
        TreeNode parentNode = targetNode;

        // Confirm that the node at the drop location is not 
        // the dragged node and that target node isn't null
        // (for example if you drag outside the control)
        if (!draggedNode.Equals(targetNode) && targetNode != null)
        
            bool canDrop = true;

            // Crawl our way up from the node we dropped on to find out if
            // if the target node is our parent. 
            while (canDrop && (parentNode != null))
            
                canDrop = !Object.ReferenceEquals(draggedNode, parentNode);
                parentNode = parentNode.Parent;
            

            // Is this a valid drop location?
            if (canDrop)
            
                // Yes. Move the node, expand it, and select it.
                draggedNode.Remove();
                targetNode.Nodes.Add(draggedNode);
                targetNode.Expand();
            
        
    

    // Optional: Select the dropped node and navigate (however you do it)
    treeView1.SelectedNode = draggedNode;
    // NavigateToContent(draggedNode.Tag);

【讨论】:

以上是关于C# WinForms - 在同一 TreeViewControl 中拖放的主要内容,如果未能解决你的问题,请参考以下文章

尝试在同一连接中运行多个命令时 C# Winforms Npgsql 3.0.5“操作已在进行中”错误

使用 PostgreSql 和 ADO.NET 在 C# WinForms 中锁定记录和表

c# 中的解决方案架构,其中 winforms 和 asp.mvc 共享业务逻辑和数据访问 [关闭]

WinForms C#中自定义对象类型的跨进程拖放

在C#的同一个异步线程中运行不同的任务[重复]

在 c# winforms 中扩展文本框