エクスプローラのフォルダがドラッグ&ドロップによりコピーや移動ができるのと同じように、ツリービューのノードをドラッグ&ドロップでコピーや移動できるようにしてみましょう。なお、ドラッグ&ドロップの方法に関する説明はこちらでしていますので、ここでは一切いたしません。
この方法について、「マイクロソフト サポート技術情報」の「[HOW TO] Visual Basic .NET アプリケーションにツリー ビューのドラッグ アンド ドロップ機能を追加する方法」「[HOW TO] Visual C# .NET アプリケーションにツリー ビューのドラッグ アンド ドロップ機能を追加する方法」でも紹介されているようですが、ここで紹介するコードはこれをさらに拡張したような感じになっています(このサンプルコードを書き終えてからこのようなページがあることを知りました)。具体的には、以下のような点が拡張されています。
以下のサンプルコードでは、フォームにツリービューコントロールTreeView1が追加されており、TreeView1内のノードをドラッグ&ドロップにより移動、コピーできるようにしています。
'フォームのLoadイベントハンドラ Private Sub Form1_Load(ByVal sender As Object, _ ByVal e As EventArgs) Handles MyBase.Load 'TreeView1へのドラッグを受け入れる TreeView1.AllowDrop = True 'ノードを追加する TreeView1.Nodes.Add("いち") TreeView1.Nodes(0).Nodes.Add("よん") TreeView1.Nodes(0).Nodes(0).Nodes.Add("ご") TreeView1.Nodes.Add("に") TreeView1.Nodes.Add("さん") 'イベントハンドラを追加する AddHandler TreeView1.ItemDrag, AddressOf TreeView1_ItemDrag AddHandler TreeView1.DragOver, AddressOf TreeView1_DragOver AddHandler TreeView1.DragDrop, AddressOf TreeView1_DragDrop End Sub 'ノードがドラッグされた時 Private Sub TreeView1_ItemDrag(ByVal sender As Object, _ ByVal e As ItemDragEventArgs) Dim tv As TreeView = CType(sender, TreeView) tv.SelectedNode = CType(e.Item, TreeNode) tv.Focus() 'ノードのドラッグを開始する Dim dde As DragDropEffects = _ tv.DoDragDrop(e.Item, DragDropEffects.All) '移動した時は、ドラッグしたノードを削除する If (dde And DragDropEffects.Move) = DragDropEffects.Move Then tv.Nodes.Remove(CType(e.Item, TreeNode)) End If End Sub 'ドラッグしている時 Private Sub TreeView1_DragOver(ByVal sender As Object, _ ByVal e As DragEventArgs) 'ドラッグされているデータがTreeNodeか調べる If e.Data.GetDataPresent(GetType(TreeNode)) Then If (e.KeyState And 8) = 8 And _ (e.AllowedEffect And DragDropEffects.Copy) = _ DragDropEffects.Copy Then 'Ctrlキーが押されていればCopy '"8"はCtrlキーを表す e.Effect = DragDropEffects.Copy ElseIf (e.AllowedEffect And DragDropEffects.Move) = _ DragDropEffects.Move Then '何も押されていなければMove e.Effect = DragDropEffects.Move Else e.Effect = DragDropEffects.None End If Else 'TreeNodeでなければ受け入れない e.Effect = DragDropEffects.None End If 'マウス下のNodeを選択する If e.Effect <> DragDropEffects.None Then Dim tv As TreeView = CType(sender, TreeView) 'マウスのあるNodeを取得する Dim target As TreeNode = _ tv.GetNodeAt(tv.PointToClient(New Point(e.X, e.Y))) 'ドラッグされているNodeを取得する Dim [source] As TreeNode = _ CType(e.Data.GetData(GetType(TreeNode)), TreeNode) 'マウス下のNodeがドロップ先として適切か調べる If Not target Is Nothing AndAlso _ Not target Is [source] AndAlso _ Not IsChildNode([source], target) Then 'Nodeを選択する If target.IsSelected = False Then tv.SelectedNode = target End If Else e.Effect = DragDropEffects.None End If End If End Sub 'ドロップされたとき Private Sub TreeView1_DragDrop(ByVal sender As Object, _ ByVal e As DragEventArgs) 'ドロップされたデータがTreeNodeか調べる If e.Data.GetDataPresent(GetType(TreeNode)) Then Dim tv As TreeView = CType(sender, TreeView) 'ドロップされたデータ(TreeNode)を取得 Dim [source] As TreeNode = _ CType(e.Data.GetData(GetType(TreeNode)), TreeNode) 'ドロップ先のTreeNodeを取得する Dim target As TreeNode = _ tv.GetNodeAt(tv.PointToClient(New Point(e.X, e.Y))) 'マウス下のNodeがドロップ先として適切か調べる If Not target Is Nothing AndAlso _ Not target Is [source] AndAlso _ Not IsChildNode([source], target) Then 'ドロップされたNodeのコピーを作成 Dim cln As TreeNode = CType([source].Clone(), TreeNode) 'Nodeを追加 target.Nodes.Add(cln) 'ドロップ先のNodeを展開 target.Expand() '追加されたNodeを選択 tv.SelectedNode = cln Else e.Effect = DragDropEffects.None End If Else e.Effect = DragDropEffects.None End If End Sub ''' <summary> ''' あるTreeNodeが別のTreeNodeの子ノードか調べる ''' </summary> ''' <param name="parentNode">親ノードか調べるTreeNode</param> ''' <param name="childNode">子ノードか調べるTreeNode</param> ''' <returns>子ノードの時はTrue</returns> Private Shared Function IsChildNode( _ ByVal parentNode As TreeNode, _ ByVal childNode As TreeNode) As Boolean If childNode.Parent Is parentNode Then Return True ElseIf Not childNode.Parent Is Nothing Then Return IsChildNode(parentNode, childNode.Parent) Else Return False End If End Function
//フォームのLoadイベントハンドラ private void Form1_Load(object sender, System.EventArgs e) { //TreeView1へのドラッグを受け入れる TreeView1.AllowDrop = true; //ノードを追加する TreeView1.Nodes.Add("いち"); TreeView1.Nodes[0].Nodes.Add("よん"); TreeView1.Nodes[0].Nodes[0].Nodes.Add("ご"); TreeView1.Nodes.Add("に"); TreeView1.Nodes.Add("さん"); //イベントハンドラを追加する TreeView1.ItemDrag += new ItemDragEventHandler(TreeView1_ItemDrag); TreeView1.DragOver += new DragEventHandler(TreeView1_DragOver); TreeView1.DragDrop += new DragEventHandler(TreeView1_DragDrop); } //ノードがドラッグされた時 private void TreeView1_ItemDrag(object sender, ItemDragEventArgs e) { TreeView tv = (TreeView) sender; tv.SelectedNode = (TreeNode) e.Item; tv.Focus(); //ノードのドラッグを開始する DragDropEffects dde = tv.DoDragDrop(e.Item, DragDropEffects.All); //移動した時は、ドラッグしたノードを削除する if ((dde & DragDropEffects.Move) == DragDropEffects.Move) tv.Nodes.Remove((TreeNode) e.Item); } //ドラッグしている時 private void TreeView1_DragOver(object sender, DragEventArgs e) { //ドラッグされているデータがTreeNodeか調べる if (e.Data.GetDataPresent(typeof(TreeNode))) { if ((e.KeyState & 8) == 8 && (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy) //Ctrlキーが押されていればCopy //"8"はCtrlキーを表す e.Effect = DragDropEffects.Copy; else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move) //何も押されていなければMove e.Effect = DragDropEffects.Move; else e.Effect = DragDropEffects.None; } else //TreeNodeでなければ受け入れない e.Effect = DragDropEffects.None; //マウス下のNodeを選択する if (e.Effect != DragDropEffects.None) { TreeView tv = (TreeView) sender; //マウスのあるNodeを取得する TreeNode target = tv.GetNodeAt(tv.PointToClient(new Point(e.X, e.Y))); //ドラッグされているNodeを取得する TreeNode source = (TreeNode) e.Data.GetData(typeof(TreeNode)); //マウス下のNodeがドロップ先として適切か調べる if (target != null && target != source && !IsChildNode(source, target)) { //Nodeを選択する if (target.IsSelected == false) tv.SelectedNode = target; } else e.Effect = DragDropEffects.None; } } //ドロップされたとき private void TreeView1_DragDrop(object sender, DragEventArgs e) { //ドロップされたデータがTreeNodeか調べる if (e.Data.GetDataPresent(typeof(TreeNode))) { TreeView tv = (TreeView) sender; //ドロップされたデータ(TreeNode)を取得 TreeNode source = (TreeNode) e.Data.GetData(typeof(TreeNode)); //ドロップ先のTreeNodeを取得する TreeNode target = tv.GetNodeAt(tv.PointToClient(new Point(e.X, e.Y))); //マウス下のNodeがドロップ先として適切か調べる if (target != null && target != source && !IsChildNode(source, target)) { //ドロップされたNodeのコピーを作成 TreeNode cln = (TreeNode) source.Clone(); //Nodeを追加 target.Nodes.Add(cln); //ドロップ先のNodeを展開 target.Expand(); //追加されたNodeを選択 tv.SelectedNode = cln; } else e.Effect = DragDropEffects.None; } else e.Effect = DragDropEffects.None; } /// <summary> /// あるTreeNodeが別のTreeNodeの子ノードか調べる /// </summary> /// <param name="parentNode">親ノードか調べるTreeNode</param> /// <param name="childNode">子ノードか調べるTreeNode</param> /// <returns>子ノードの時はTrue</returns> private static bool IsChildNode(TreeNode parentNode, TreeNode childNode) { if (childNode.Parent == parentNode) return true; else if (childNode.Parent != null) return IsChildNode(parentNode, childNode.Parent); else return false; }