c# - net - Mueve el nodo en el árbol hacia arriba o hacia abajo
treeview vb.net 2010 ejemplos (3)
¿Cuál es la forma más precisa de mover un nodo hacia arriba y hacia abajo en una vista de árbol? Obtuve un menú contextual en cada nodo y el nodo seleccionado debería moverse con todos sus subnodos.
Estoy usando WinForms C # .Net 3.5
Aquí hay una solución que te permite arrastrar y soltar nodos a donde quieras. Para mover un nodo al mismo nivel que otro nodo, simplemente mantenga presionada la tecla shift cuando suelte el nodo. Esta es una manera realmente fácil de ir en comparación con las alternativas y sus posibles problemas. El ejemplo fue escrito con una versión más reciente de .Net (4.5).
Nota: Asegúrese de que y AllowDrop = true en el control de vista de árbol, de lo contrario no podrá descartar nodos.
/// <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);
}
Si bien creo que escribir este código es una pérdida de tiempo, dada la falta de respuesta a los comentarios del OP, lo menos que puedo hacer es mostrar cómo se puede corregir el ejemplo de código de Le-Savard para que los clics múltiples de arriba a abajo elección en el menú contextual ... asumiendo que el menú contextual no se cierra automáticamente cada vez y el usuario se ve obligado a seleccionar el mismo nodo una y otra vez ... hará lo correcto con el nodo seleccionado de forma original, y no creará efectos secundarios no deseados:
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;
}
}
}
}
Por supuesto, esta solución aún no aborda el hecho de que en el código de ejemplo no se pueden mover varios nodos raíz (ya que no tienen padres): eso es fácil de arreglar.
Tampoco aborda el caso más interesante en el que subir a un nodo secundario superior significa que usted hace una interpretación de dónde debe ir ese código de niño "promovido": exactamente la misma "elección estratégica" está involucrada donde "muda" el último hijo nodo de un nodo primario y, por lo tanto, se les exige que decidan a dónde deben ir. En el código de Dynami Le-Savard: estos casos son ignorados.
Sin embargo, es una opción de diseño restringir que los nodos secundarios solo se muevan dentro de sus nodos primarios. Colección de nodos: una opción de diseño que puede ser perfectamente adecuada para una solución.
De manera similar, es una opción de diseño para obligar a un usuario a seleccionar un nodo y hacer clic en el contexto para obtener un menú contextual que permite una opción de subir o bajar cada vez que quiera moverlo : esa no es una opción de diseño. marca: estaría usando la función de arrastrar y soltar aquí o los botones que permiten la reubicación rápida repetida de cualquier nodo seleccionado en cualquier lugar del árbol.
Por cierto, me gusta el uso de las extensiones de Dynami Le-Savard aquí.
Puedes usar las siguientes extensiones:
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);
}
}
}
}
Los nodos hijos seguirán a sus padres.
EDITAR: el caso agregado de que el nodo a mover es una raíz en el TreeView.