向上或向下移动树中的节点

Kai*_*Kai 17 c# treeview winforms

在树视图中上下移动节点的最准确方法是什么.我在每个节点上都有一个上下文菜单,所选节点应该随其所有子节点一起移动.

我正在使用C#.Net 3.5 WinForms

Dyn*_*ard 38

您可以使用以下扩展名:

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);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

子节点将跟随他们的父母.

编辑:添加了一个案例,即要移动的节点是TreeView中的根.

  • 为了获得最佳结果,请添加“view.BeginUpdate()”、“view.EndUpdate()”和“node.TreeView.SelectedNode = node”。 (2认同)
  • int index = parent.Nodes.IndexOf(node); 这可以用'int index = node.Index;'代替 (2认同)

Bil*_*llW 8

虽然我觉得编写这段代码是浪费时间,但由于对OP的评论缺乏回应,我至少可以做的是展示如何修复Le-Savard的代码示例,以便多次点击向上或向下选择上下文菜单...假设每次上下文菜单都没有自动关闭,并且用户被迫一遍又一遍地选择同一个节点...将使用orignally selected节点做正确的事情,而不是创建无意的副作用:

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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,这个修复仍然没有解决在示例代码中无法移动多个根节点的事实(因为它们是'无父对象的):这很容易解决.

它也没有解决更有趣的情况,即提升顶级子节点意味着你对"促进"子代码应该去的地方做出一些解释:在你"向下移动"最后一个孩子时会涉及完全相同的"战略选择"父节点的节点因此需要决定它应该去哪里.在Dynami Le-Savard的代码中:这些案例被忽略了.

然而,这是一个设计选择,以从它们的父节点的节点集合中仅被移动限制子节点:一个设计选择,其可以是完全适合的解决方案.

类似地,强制用户选择节点和上下文单击以获取上下文菜单是一种设计选择,该菜单允许选择每次移动它时向上或向下移动:这不是设计选择我是make:我在这里使用拖放或按钮,允许在树中的任何位置重复快速重新定位任何选定节点.

顺便说一句,我喜欢Dynami Le-Savard在这里使用扩展.