С# WinForms - DragDrop внутри одного TreeViewControl

Я пытаюсь реализовать DragDrop элемента treeview внутри одного элемента управления.

Я хочу иметь возможность перемещать элемент из 1 node в другой.

Вот мой текущий код. Когда я запустил это, я вижу, что элемент начал перетаскивание, но значок Windows не позволяет его удалять на любые узлы в элементе управления.

Мой текущий код

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();
    }
}

Ответ 2

Установите AllowDrop=true в дереве управления.

Ответ 3

немного улучшенная версия, которая мешает вам сбросить node на себя или на любого из его потомков

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, чтобы выполнить все другие изменения.

Добавлена ​​поддержка:

  • Поддерживает удаление узлов на фоне дерева (внизу). Узлы добавляются в нижней части дерева.
  • Включить пример "не качать на дочерний node" mrpurple и ухаживать за ним, чтобы он был встроен в исходный пример.
  • Также сделал так, что после того, как он упал, выбирается перетаскиваемый node. Рекомендуем загружать содержимое для отброшенного node здесь, иначе в противном случае пользователь может запутаться в том, что отображается в настоящее время, и что выбрано node.

Примечание. Убедитесь, что AllowDrop = true в элементе управления treeview, иначе вы не сможете удалить узлы.

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);
}