Working with a Windows Forms .NET TreeView control? This article contains code samples for the most common questions I've recevied. Things such as right click on nodes to show context menues, drag and drop nodes on the same TreeView or even another control, nudge nodes up and down in sibling order, and much more.
1. Right Click Show Context Menu:
Code
private ContextMenu tvSample1Menu = new ContextMenu();
private TreeView tvSample = new TreeView();
private void tvSample_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
TreeViewUtil.SetSelectedNodeByPosition(tvSample,e.X,e.Y);
if (tvSample.SelectedNode == null) { return; }
if (e.Button == MouseButtons.Right) { return; }
}
private void tvSample_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
switch (e.Button)
{
case MouseButtons.Right:
tvSample1Menu.Show(tvSample,new Point(e.X,e.Y));
break;
default:
break;
}
}
public void SetSelectedNodeByPosition(TreeView tv,
int mouseX,
int mouseY)
{
TreeNode node = null;
try
{
Point pt = new Point(mouseX,mouseY);
tv.PointToClient(pt);
node = tv.GetNodeAt(pt);
tv.SelectedNode = node;
if (node == null) return;
if (!node.Bounds.Contains(pt)) { return; }
}
catch { }
return;
}
2. Show Context Menu dynamically on selected node.
This method uses the placement on screen of the
selected node. ContextMenus can be draw by position.
Also, you could just as easily programmatically create
the ContextMenu versus passing one in like this:
Code
public void ShowContextMenu(TreeView tv,ContextMenu menu)
{
try
{
Point pt = new Point(tv.SelectedNode.Bounds.Left,
tv.SelectedNode.Bounds.Bottom);
menu.Show(tv,pt);
}
catch (Exception) { throw; }
}
3. Nudge TreeNode Sibling Order Up Or Down:
Code
public bool NudgeDown(TreeNode node)
{
int newIndex = 0;
TreeNode nodeClone = null;
try
{
if (node == null) { return false; }
newIndex = node.Index + 2;
if (newIndex > node.Parent.Nodes.Count) { return false; }
nodeClone = (TreeNode)node.Clone();
node.Parent.Nodes.Insert(newIndex, nodeClone);
node.Parent.Nodes.Remove(node);
nodeClone.TreeView.SelectedNode = nodeClone;
}
catch (Exception) { throw; }
return true;
}
public bool NudgeUp(TreeNode node)
{
int newIndex = 0;
TreeNode nodeClone = null;
try
{
if (node == null) { return false; }
if (node.Index == 0) { return false; }
newIndex = node.Index - 1;
nodeClone = (TreeNode)node.Clone();
node.Parent.Nodes.Insert(newIndex, nodeClone);
node.Parent.Nodes.Remove(node);
nodeClone.TreeView.SelectedNode = nodeClone;
}
catch (Exception) { throw; }
return true;
}
4. Drag And Drop On Same TreeView or Different Treeview Control.
Download the code sample for additional information.
Code
Form Events
private void tvSample_ItemDrag(object sender,
System.Windows.Forms.ItemDragEventArgs e)
{
DoDragDrop(e.Item, DragDropEffects.Move);
}
private void tvSample_DragEnter(object sender,
System.Windows.Forms.DragEventArgs e)
{
this.DragEnter((TreeView)sender,e);
}
private void tvSample_DragOver(object sender,
System.Windows.Forms.DragEventArgs e)
{
this.DragOver((TreeView)sender,e);
}
private void tvSample_DragDrop(object sender,
System.Windows.Forms.DragEventArgs e)
{
bool dropOnNewControl = false;
try
{
this.DragDrop((TreeView)sender,e,ref dropOnNewControl);
if (dropOnNewControl)
{
// Perform action on old and
// new control
}
}
catch (Exception err) { Messagebox.Show(err.Message); }
}
Resuable methods
public void DragOver(TreeView tv,System.Windows.Forms.DragEventArgs e)
{
try
{
if (!e.Data.GetDataPresent(NodeObjectName, true)) { return; }
Point pt = tv.PointToClient(new Point(e.X,e.Y));
TreeNode tgtnode = tv.GetNodeAt(pt);
if (tv.SelectedNode != tgtnode)
{
tv.SelectedNode = tgtnode;
TreeNode drop = (TreeNode)e.Data.GetData(NodeObjectName);
while (tgtnode != null)
{
if (tgtnode == drop)
{
e.Effect = DragDropEffects.None;
return;
}
tgtnode = tgtnode.Parent;
}
}
e.Effect = DragDropEffects.Move;
}
catch (Exception) { throw; }
}
public void DragDrop(TreeView tv,
System.Windows.Forms.DragEventArgs e,
ref bool dropOnNewControl)
{
try
{
dropOnNewControl = false;
// Was the target control enabled to accept controls
// being dropped on it and was it successful?
if (!e.Data.GetDataPresent(NodeObjectName,true)) { return; }
// If not working solely with TreeViews,you'll
// to perform a .GetType() on .GetData prior to casting
// to a specific object.
TreeNode drop = (TreeNode)e.Data.GetData(NodeObjectName);
TreeNode tgtnode = tv.SelectedNode;
if (drop == drop.TreeView.Nodes[0])
{
// the drop node is the root of the tree.
// You may not want to permit this.
return;
}
if (drop == tgtnode)
{
// Jump out if dropped on self.
return;
}
if (tgtnode.TreeView == drop.TreeView)
{
// If same control, act accordingly
}
else
{
dropOnNewControl = true;
// This is a different control that the node
// was dropped on. You may now need to sync
up the old object's underlying data.
}
// This removes the TreeNodes from the TreeView.
drop.Remove();
if (tgtnode == null)
{
tv.Nodes.Add(drop);
}
else
{
tgtnode.Nodes.Add(drop);
}
drop.EnsureVisible();
tv.SelectedNode = drop;
}
catch (Exception) { throw; }
}
Please download the working sample. It is derived from an old article I did
on an alternative approach concerning data binding a DataSet to a TreeView.
Download.