ツリービューでノードを上下に移動する最も正確な方法は何ですか。各ノードにコンテキストメニューが表示され、選択したノードをすべてのサブノードとともに移動する必要があります。
C#.Net 3.5WinFormsを使用しています
次の拡張機能を使用できます。
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のルートである場合を追加しました。
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がここで拡張機能を使用しているのが好きです。
これは、ノードを好きな場所にドラッグアンドドロップできるソリューションです。ノードを別のノードと同じレベルに移動するには、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);
}