The Treeview control does not support multiple selections but there are samples posted at GotDotNet which demonstrates how this feature can be implemented.
In a posting in the Microsoft.Windows.Forms newsgroup, Brian Roder (Microsoft) gives VB.Net code snippets to handle the DragEnter, ItemDrag and DragDrop events that provide a solution to this problem. You can get C# code in this sample, TreeViewDnD. Here is some sample handlers.
You can display a context menu when a user right-clicks on a node by listening to the TreeView’s MouseUp event as shown below:
[C#]
privatevoidtreeView1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
if(e.Button == MouseButtons.Right)
{
Point ClickPoint = new Point(e.X,e.Y);
TreeNode ClickNode = treeView1.GetNodeAt(ClickPoint);
if(ClickNode == null) return;
// Convert from Tree coordinates to Screen coordinates
Point ScreenPoint = treeView1.PointToScreen(ClickPoint);
// Convert from Screen coordinates to Form coordinates
Point FormPoint = this.PointToClient(ScreenPoint);
// Show context menu
contextmenu.MenuItems.Clear();
contextmenu.MenuItems.Add('Item1');
contextmenu.MenuItems.Add('Item2');
contextmenu.Show(this,FormPoint);
}
}
[VB.NET]
Private Sub treeView1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
If e.Button = MouseButtons.Right Then
Dim ClickPoint As Point = New Point(e.X,e.Y)
Dim ClickNode As TreeNode = treeView1.GetNodeAt(ClickPoint)
If ClickNode Is Nothing Then
Return
End If
’ Convert from Tree coordinates to Screen coordinates
Dim ScreenPoint As Point = treeView1.PointToScreen(ClickPoint)
’ Convert from Screen coordinates to Form coordinates
Dim FormPoint As Point = Me.PointToClient(ScreenPoint)
’ Show context menu
contextmenu.MenuItems.Clear()
contextmenu.MenuItems.Add('Item1')
contextmenu.MenuItems.Add('Item2')
contextmenu.Show(this,FormPoint)
End If
End Sub
A click event will be fired but a node will not be selected when the user clicks to the right of a node. This code snippets show how you can ensure that a node is selected in this scenario:
[C#]
privatevoidtreeView1_Click(object sender, System.EventArgs e)
{
treeView1.SelectedNode = treeView1.GetNodeAt(treeView1.PointToClient(Cursor.Position));
}
[VB.NET]
Private Sub treeView1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
treeView1.SelectedNode = treeView1.GetNodeAt(treeView1.PointToClient(Cursor.Position))
End Sub
You need to set the HideSelection property of the TreeView to false and call:
[C#]
//Select the first nodethis.treeView1.SelectedNode = this.treeView1.Nodes[0];
[VB.NET]
’Select the first node
Me.treeView1.SelectedNode = Me.treeView1.Nodes(0)
The following code snippet demonstrates how you can clone or copy all the nodes in TreeView1 to TreeView2 by clicking on Button1.
[C#]
privatevoidIterateTreeNodes (TreeNode originalNode, TreeNode rootNode)
{
foreach( TreeNode childNode in originalNode.Nodes)
{
TreeNode newNode = new TreeNode(childNode.Text);
newNode.Tag = childNode.Tag;
this.treeView2.SelectedNode = rootNode;
this.treeView2.SelectedNode.Nodes.Add(newNode);
IterateTreeNodes(childNode, newNode);
}
}
//Button Click codeprivatevoidbutton1_Click(object sender, System.EventArgs e)
{
foreach( TreeNode originalNode inthis.treeView1.Nodes)
{
TreeNode newNode = new TreeNode(originalNode.Text);
newNode.Tag = originalNode.Tag;
this.treeView2.Nodes.Add(newNode);
IterateTreeNodes(originalNode, newNode);
}
}
[VB.NET]
Private Sub IterateTreeNodes(ByVal originalNode As TreeNode, ByVal rootNode As TreeNode)
Dim childNode As TreeNode
For Each childNode In originalNode.Nodes
Dim NewNode As TreeNode = New TreeNode(childNode.Text)
NewNode.Tag = childNode.Tag
Me.treeView2.SelectedNode = rootNode
Me.treeView2.SelectedNode.Nodes.Add(NewNode)
IterateTreeNodes(childNode, NewNode)
Next
End Sub
’Button Click code
Private Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim originalNode As TreeNode
For Each originalNode In Me.treeView1.Nodes
Dim NewNode As TreeNode = New TreeNode(originalNode.Text)
NewNode.Tag = originalNode.Tag
Me.treeView2.Nodes.Add(NewNode)
IterateTreeNodes(originalNode, NewNode)
Next
End Sub
Here is a code snippet suggested by Mattias Sjögren on the microsoft.public.dotnet.languages.csharp newsgroup.
[C#]public int NodeLevel(TreeNode node)
{
int level = 0;
while ((node = node.Parent) != null) level++;
return level;
}
[VB.NET]
Public Sub NodateLevel(ByVal node as TreeNode) As Integer
Dim level as Integer = 0While Not node Is Nothing
node = node.Parent
level = level + 1
End While
End Sub
Try using a MouseMove event handler and checking to see if you have moved to a new node, and if so, set a new tiptext.
[C#]
privateint oldNodeIndex = -1;
private ToolTip toolTip1;
privatevoidForm1_Load(object sender, System.EventArgs e)
{
this.toolTip1 = new System.Windows.Forms.ToolTip();
this.toolTip1.InitialDelay = 300; //half a second delaythis.toolTip1.ReshowDelay = 0;
}
privatevoidtreeView1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
TreeNode tn = this.treeView1.GetNodeAt(e.X, e.Y);
if(tn != null)
{
int currentNodeIndex = tn.Index;
if(currentNodeIndex != oldNodeIndex)
{
oldNodeIndex = currentNodeIndex;
if(this.toolTip1 != null && this.toolTip1.Active)
this.toolTip1.Active = false; //turn it offthis.toolTip1.SetToolTip(this.treeView1, string.Format('tooltip: node {0}', oldNodeIndex));
this.toolTip1.Active = true; //make it active so it can show
}
}
}
[VB.NET]
Private oldNodeIndex As Integer = - 1Private toolTip1 As ToolTip
Private Sub Form1_Load(sender As Object, e As System.EventArgs)
Me.toolTip1 = New System.Windows.Forms.ToolTip()
Me.toolTip1.InitialDelay = 300 ’half a second delay
Me.toolTip1.ReshowDelay = 0
End Sub ’Form1_Load
Private Sub treeView1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs)
Dim tn As TreeNode = Me.treeView1.GetNodeAt(e.X, e.Y)
If Not (tn Is Nothing) Then
Dim currentNodeIndex As Integer = tn.Index
If currentNodeIndex <> oldNodeIndex Then
oldNodeIndex = currentNodeIndex
If Not (Me.toolTip1 Is Nothing) And Me.toolTip1.Active Then
Me.toolTip1.Active = False ’turn it off
End If
Me.toolTip1.SetToolTip(Me.treeView1, String.Format('tooltip: node {0}', oldNodeIndex))
Me.toolTip1.Active = True ’make it active so it can show
End If
End If
End Sub ’treeView1_MouseMove
When you drag an item within the TreeView, you can handle the DragOver event for a drag-drop. If you want to drag-drop into a spot that’s not currently visible, you can scroll the TreeView by handling the DragOver event:
[C#]privatevoid treeView1_DragOver(object sender, System.Windows.Forms.DragEventArgs e){TreeViewtv = sender as TreeView;Pointpt = tv.PointToClient(new Point(e.X,e.Y));intdelta = tv.Height - pt.Y;if((delta < tv.Height / 2) && (delta > 0)){TreeNodetn = tv.GetNodeAt(pt.X, pt.Y);if(tn.NextVisibleNode != null)tn.NextVisibleNode.EnsureVisible();}if((delta > tv.Height / 2) && (delta < tv.Height)){TreeNodetn = tv.GetNodeAt(pt.X, pt.Y);if(tn.PrevVisibleNode != null)tn.PrevVisibleNode.EnsureVisible();}}[VB.NET]PrivateSub treeView1_DragOver(sender As Object, e As System.Windows.Forms.DragEventArgs)IfTypeOf sender is TreeView ThenDimtv As TreeView = CType(sender, TreeView) Dimpt As Point = tv.PointToClient(New Point(e.X, e.Y))Dimdelta As Integer = tv.Height - pt.YIfdelta < tv.Height / 2 And delta > 0 ThenDimtn As TreeNode = tv.GetNodeAt(pt.X, pt.Y)IfNot (tn.NextVisibleNode Is Nothing) Thentn.NextVisibleNode.EnsureVisible()EndIf EndIf Ifdelta > tv.Height / 2 And delta < tv.Height ThenDimtn As TreeNode = tv.GetNodeAt(pt.X, pt.Y)IfNot (tn.PrevVisibleNode Is Nothing) Thentn.PrevVisibleNode.EnsureVisible()EndIf EndIf EndIfEndSub ’treeView1_DragOver
Try using the AfterSelect event instead of the Click event. The Click event is inherited from Control.Click and occurs before the new selection is set into SelectedNode. The AfterSelect event is fired after the newly selected node is placed in the SelectedNode property. This code illustrates these events.