web-dev-qa-db-ja.com

ツリー上または下に移動Node

ツリービューでノードを上下に移動する最も正確な方法は何ですか。各ノードにコンテキストメニューが表示され、選択したノードをすべてのサブノードとともに移動する必要があります。

C#.Net 3.5WinFormsを使用しています

17
Kai

次の拡張機能を使用できます。

public static class Extensions
{
    public static void MoveUp(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index > 0)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index - 1, node);
            }
        }
        else if (node.TreeView.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index > 0)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index - 1, node);
            }
        }
    }

    public static void MoveDown(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        TreeView view = node.TreeView;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index < parent.Nodes.Count -1)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index + 1, node);
            }
        }
        else if (view != null && view.Nodes.Contains(node)) //root node
        {
            int index = view.Nodes.IndexOf(node);
            if (index < view.Nodes.Count - 1)
            {
                view.Nodes.RemoveAt(index);
                view.Nodes.Insert(index + 1, node);
            }
        }
    }
}

子ノードは親に従います。

編集:移動するノードがTreeViewのルートである場合を追加しました。

40

OPによるコメントへの応答がないことを考えると、このコードを書くのは時間の無駄だと思いますが、私にできることは、Le-Savardによるコード例を修正して、上下に複数回クリックする方法を示すことです。コンテキストメニューでの選択...コンテキストメニューが毎回自動で閉じられず、ユーザーが同じノードを何度も選択する必要があると仮定すると...最初に選択されたノードで正しいことを行い、作成しません意図しない副作用:

public static class Extensions
{
    public static void MoveUp(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index > 0)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index - 1, node);

                // bw : add this line to restore the originally selected node as selected
                node.TreeView.SelectedNode = node;
            }
        }
    }

    public static void MoveDown(this TreeNode node)
    {
        TreeNode parent = node.Parent;
        if (parent != null)
        {
            int index = parent.Nodes.IndexOf(node);
            if (index < parent.Nodes.Count - 1)
            {
                parent.Nodes.RemoveAt(index);
                parent.Nodes.Insert(index + 1, node);

                // bw : add this line to restore the originally selected node as selected
                node.TreeView.SelectedNode = node;
            }
        }
    }
}

もちろん、この修正は、サンプルコードで複数のルートノードを移動できないという事実に対処していません(それらは親がないため):それは簡単に修正できます。

また、最上位の子ノードを上に移動すると、その「プロモートされた」子コードがどこに移動するかを解釈するという、より興味深いケースにも対応していません。最後の子を「下に移動」する場合とまったく同じ「戦略的選択」が関係します。親ノードのノードであるため、どこに移動するかを決定する必要があります。 Dynami Le-Savardのコードでは、これらのケースは無視されます。

ただし、子ノードが親ノード内でのみ移動されるように制限するのはdesign-choiceです。Nodesコレクション:1つのソリューションに完全に適している可能性のある設計上の選択。

同様に、設計上の選択ユーザーにノードの選択を強制し、コンテキストクリックして、上下に移動することを選択できるコンテキストメニューを取得します必要なときに毎回)移動:これは私が行う設計上の選択ではありません:ここでドラッグアンドドロップを使用するか、ツリー内の任意の場所で選択したノードを繰り返し高速で再配置できるボタンを使用します。

ちなみに、DynamiLe-Savardがここで拡張機能を使用しているのが好きです。

9
BillW

これは、ノードを好きな場所にドラッグアンドドロップできるソリューションです。ノードを別のノードと同じレベルに移動するには、Shiftキーを押しながらノードをドロップします。これは、代替案とその潜在的な問題と比較して、非常に簡単な方法です。例は、より新しいバージョンの.Net(4.5)で作成されました。

注:ツリービューコントロールで必ずAllowDrop = trueを指定してください。そうしないと、ノードをドロップできません。

/// <summary>
/// Handle user dragging nodes in treeview
/// </summary>
private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
{
    DoDragDrop(e.Item, DragDropEffects.Move);
}

/// <summary>
/// Handle user dragging node into another node
/// </summary>
private void treeView1_DragEnter(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Move;
}

/// <summary>
/// Handle user dropping a dragged node onto another node
/// </summary>
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 that was dragged.
    TreeNode draggedNode = e.Data.GetData(typeof(TreeNode));

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

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

    // Did the user drop the node 
    if (targetNode == null)
    {
        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;
            while (canDrop && (parentNode != null))
            {
                canDrop = !Object.ReferenceEquals(draggedNode, parentNode);
                parentNode = parentNode.Parent;
            }

            if (canDrop)
            {
                // Have to remove nodes before you can move them.
                draggedNode.Remove();

                // Is the user holding down shift?
                if (e.KeyState == 4)
                {
                    // Is the targets parent node null?
                    if (targetNode.Parent == null)
                    {
                        // The target node has no parent. That means 
                        // the target node is at the root level. We'll 
                        // insert the node at the root level below the 
                        // target node.
                        treeView1.Nodes.Insert(targetNode.Index + 1, draggedNode);
                    }
                    else 
                    {
                        // The target node has a valid parent so we'll 
                        // drop the node into it's index.
                        targetNode.Parent.Nodes.Insert(targetNode.Index + 1, draggedNode);
                    }
                }
                else
                { 
                    targetNode.Nodes.Add(draggedNode);
                }

                targetNode.Expand();
            }
        }
    }

    // Optional: The following lines are an example of how you might
    // provide a better experience by highlighting and displaying the 
    // content of the dropped node. 
    // treeView1.SelectedNode = draggedNode;
    // NavigateToNodeContent(draggedNode.Tag); 
}
2
GrayDwarf