chocolade Ответов: 1

Как я могу перетащить узел в treeview, но он будет находиться на уровне глубины узла ?


В этом коде я могу перетаскивать узлы и менять их местами.

Проблема заключается в том, что если я перетащу дочерний узел на любой уровень глубины, он опустит узел/ы на верхний корневой уровень 0.

Мне нужно знать, как сохранить уровень глубины узлов, чтобы, например, если я перетаскиваю узел на уровне глубины 3, то узел должен двигаться по индексам уровня 3, а не уровня 0.

Но как мне сказать ему, чтобы он перетаскивался на уровне узла ?

<pre>using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

public class AdvancedTreeView : TreeView
{
    private Bitmap openedIcon, closedIcon;
    private List<TreeNode> rootNodes = new List<TreeNode>();

    public AdvancedTreeView()
    {
        DrawMode = TreeViewDrawMode.OwnerDrawText;
        ShowLines = false;
        AlternateBackColor = BackColor;
        ArrowColor = SystemColors.WindowText;
        this.AllowDrop = true;
    }

    public Color AlternateBackColor { get; set; }
    public Color ArrowColor { get; set; }

    protected override void OnDrawNode(DrawTreeNodeEventArgs e)
    {
        // background
        Color backColor = (GetTopNodeIndex(e.Node) & 1) == 0 ? BackColor : AlternateBackColor;
        using (Brush b = new SolidBrush(backColor))
        {
            e.Graphics.FillRectangle(b, new Rectangle(0, e.Bounds.Top, ClientSize.Width, e.Bounds.Height));
        }

        // icon
        if (e.Node.Nodes.Count > 0)
        {
            Image icon = GetIcon(e.Node.IsExpanded);
            e.Graphics.DrawImage(icon, e.Bounds.Left - icon.Width - 3, e.Bounds.Top);
        }

        // text (due to OwnerDrawText mode, indenting of e.Bounds will be correct)
        TextRenderer.DrawText(e.Graphics, e.Node.Text, Font, e.Bounds, ForeColor);

        // indicate selection (if not by backColor):
        if ((e.State & TreeNodeStates.Selected) != 0)
            ControlPaint.DrawFocusRectangle(e.Graphics, e.Bounds);
    }

    protected override void OnItemDrag(ItemDragEventArgs e)
    {
        // Move the dragged node when the left mouse button is used.
        if (e.Button == MouseButtons.Left)
        {
            DoDragDrop(e.Item, DragDropEffects.Move);
        }

        // Copy the dragged node when the right mouse button is used.
        else if (e.Button == MouseButtons.Right)
        {
            DoDragDrop(e.Item, DragDropEffects.Copy);
        } 
    }

    protected override void OnDragEnter(DragEventArgs e)
    {
        e.Effect = e.AllowedEffect;
    }

    protected override void OnDragOver(DragEventArgs e)
    {
        // Retrieve the client coordinates of the mouse position.
        Point targetPoint = this.PointToClient(new Point(e.X, e.Y));

        // Select the node at the mouse position.
        this.SelectedNode = this.GetNodeAt(targetPoint);
    }

    protected override void OnDragDrop(DragEventArgs e)
    {
        // Retrieve the client coordinates of the drop location.
        Point targetPoint = this.PointToClient(new Point(e.X, e.Y));

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

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

        //draggedNode.Level;

        // Confirm that the node at the drop location is not 
        // the dragged node or a descendant of the dragged node.
        if (!draggedNode.Equals(targetNode))// && !ContainsNode(draggedNode, targetNode))
        {
            // If it is a move operation, remove the node from its current 
            // location and add it to the node at the drop location.
            if (e.Effect == DragDropEffects.Move)
            {
                // To check nad make that the indexs if the dragged and target nodes
                // Are childs to get the index of them in the place they are in the tree level
                // Now the indexs are belong to the root to the top of the tree.
                // So if a child index is 2 or 0 it will remove it and make the switch at the
                // Top level depth root. Instead where the childs are.
                int draggedLevel = draggedNode.Level;
                int targetLevel = targetNode.Level;
                int draggedindex = draggedNode.Index;
                int targetindex = targetNode.Index;

                draggedNode.Remove();
                targetNode.Remove();
                this.Nodes.Insert(targetindex, draggedNode);
                this.Nodes.Insert(draggedindex, targetNode);
            }

            // If it is a copy operation, clone the dragged node 
            // and add it to the node at the drop location.
            else if (e.Effect == DragDropEffects.Copy)
            {
                targetNode.Nodes.Add((TreeNode)draggedNode.Clone());
            }
        }
    }

    private int GetTopNodeIndex(TreeNode node)
    {
        while (node.Parent != null)
            node = node.Parent;

        return Nodes.IndexOf(node);
    }

    private Image GetIcon(bool nodeIsExpanded)
    {
        if (openedIcon == null)
            InitIcons();
        return nodeIsExpanded ? openedIcon : closedIcon;
    }

    private void InitIcons()
    {
        openedIcon = new Bitmap(16, 16);
        closedIcon = new Bitmap(16, 16);
        using (Brush b = new SolidBrush(ArrowColor))
        {
            using (Graphics g = Graphics.FromImage(openedIcon))
                g.FillPolygon(b, new[] { new Point(0, 0), new Point(15, 0), new Point(8, 15), });
            using (Graphics g = Graphics.FromImage(closedIcon))
                g.FillPolygon(b, new[] { new Point(0, 0), new Point(15, 8), new Point(0, 15), });
        }
    }
}


Часть make the drag and drop находится внутри OnDragDrop :

int draggedindex = draggedNode.Index;
int targetindex = targetNode.Index;
draggedNode.Remove();
targetNode.Remove();
this.Nodes.Insert(targetindex, draggedNode);
this.Nodes.Insert(draggedindex, targetNode);


Но опять же он опустит перетаскиваемый узел и целевой узел до уровня 0, даже если я перетащил узел на уровень 3, так как он думает, что индексы имеют уровень 0. Я не знаю, как сказать ему, чтобы он перетащил индекс уровня, на котором находятся узлы.

Этот код в форме 1 предназначен для тестирования я сделал это чтобы увидеть все уровни глубины узлов :

<pre>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Treeview_Test
{
    public partial class Form1 : Form
    {
        List<int> levels = new List<int>();

        public Form1()
        {
            InitializeComponent();

            foreach (TreeNode node in advancedTreeView1.Nodes)
            {
                ListNodes(node);
            }
        }

       
        void ListNodes(TreeNode node)
        {
            foreach (TreeNode subnode in node.Nodes)
            {
                ListNodes(subnode);
            }

            levels.Add(node.Level);
        }
    }
}


Итак, теперь я знаю, например, что в списке уровней индекс 0 находится на уровне 0, а индекс 1-на уровне 4, индекс 2-на уровне 0, индекс 3-на уровне 2, индекс 4-на уровне 3 и так далее.

Но я все еще не могу понять, как сделать это в OnDragDrop ?

Что я уже пробовал:

То, что я пробовал, не так уж много, так как я не могу понять, что делать.

BillWoodruff

"Итак, если я перетаскиваю узел на глубину уровня 3, например, так что узел должен двигаться по индексам уровня 3, а не уровня 0." Я не совсем понимаю, что это значит.

Вы имеете в виду, что хотите, чтобы отброшенный узел стал дочерним узлом узла, на который он отброшен ?

Или ты имеешь в виду что-то другое ?

1 Ответов

Рейтинг:
1

BillWoodruff

Посмотрите, что вы делаете сейчас, когда вы падаете во время движения:

int draggedLevel = draggedNode.Level;
int targetLevel = targetNode.Level;
int draggedindex = draggedNode.Index;
int targetindex = targetNode.Index;

draggedNode.Remove();
targetNode.Remove();
treeView1.Nodes.Insert(targetindex, draggedNode);
treeView1.Nodes.Insert(draggedindex, targetNode);
1 хотя этот код не использует информацию об уровне, каковы ваши намерения при записи этой информации ?

2 обе вставки находятся в коллекции узлов самого дерева (корневой уровень).

3 после вызова 'Remove на узле, этот узел все еще "там", но у него нет "родителя" или "индекса": вы необходимость эта информация должна знать, куда вставить отброшенный узел.

4 ваш код выдаст ошибку, если вы упадете на неузловую область TreeView" для обработки которой вам нужно обработать 'targetNode == null

Попробовать это:
int draggedindex = draggedNode.Index;
int targetindex = targetNode.Index;

bool isTargetNodeRoot = targetNode.Parent == null;

draggedNode.Remove();

if (isTargetNodeRoot)
{
    targetNode.Remove();

    treeView1.Nodes.Insert(targetindex, draggedNode);
    treeView1.Nodes.Insert(targetindex, targetNode);
}
else
{
    TreeNodeCollection nodes = targetNode.Parent.Nodes;
    targetNode.Remove();

    nodes.Insert(targetindex, draggedNode);
    nodes.Insert(targetindex, targetNode);
}
Примечание: почему вы думаете, что вам нужно удалить целевой узел drop, а затем добавить его обратно ?