How do I add a button beside each node of a TreeView?
Adding a button beside each node of a treeview is difficult. You would have to handle drawing of the treeview yourself, and either draw the buttons yourself and emulate their functionality, or create child button controls and display them in the right places within the tree control and then handle repositioning them when the control scrolls, etc. Either way it is going to be a nightmare.
Luckily, there is an easy way out: you do not have to do any of that complicated stuff, BECAUSE YOU SHOULD NOT DO THEM!
Have you ever seen a tree control with buttons in it? No. Therefore, if your tree control has buttons in it, it will be seen by your end users as bizarre.
What you should do is consider how other applications have solved the problem that you are trying to solve without using tree controls with buttons in them, and do as they do.
The simplest way to do this is to draw tree yourself. Here is a small example (please note that PushButtonState is located inside System.Windows.Forms.VisualStyles namespace):
public class CustomTreeView : TreeView
{
private Rectangle buttonRect = new Rectangle(80, 2, 50, 26);
private StringFormat stringFormat;
public CustomTreeView()
{
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
DrawMode = TreeViewDrawMode.OwnerDrawText;
ShowLines = false;
FullRowSelect = true;
ItemHeight = 30;
stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Near;
stringFormat.LineAlignment = StringAlignment.Center;
}
protected override void OnDrawNode(DrawTreeNodeEventArgs e)
{
e.Graphics.DrawString(e.Node.Text, this.Font, new SolidBrush(this.ForeColor), e.Bounds, stringFormat);
ButtonRenderer.DrawButton(e.Graphics, new Rectangle(e.Node.Bounds.Location + new Size(buttonRect.Location), buttonRect.Size), "btn", this.Font, true, (e.Node.Tag != null) ? (PushButtonState)e.Node.Tag : PushButtonState.Normal);
}
protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
{
if (e.Node.Tag != null && (PushButtonState)e.Node.Tag == PushButtonState.Pressed)
{
e.Node.Tag = PushButtonState.Normal;
MessageBox.Show(e.Node.Text + " clicked");
// force redraw
e.Node.Text = e.Node.Text;
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
TreeNode tnode = GetNodeAt(e.Location);
if (tnode == null) return;
Rectangle btnRectAbsolute = new Rectangle(tnode.Bounds.Location + new Size(buttonRect.Location), buttonRect.Size);
if (btnRectAbsolute.Contains(e.Location))
{
tnode.Tag = PushButtonState.Pressed;
tnode.Text = tnode.Text;
}
}
}
Also, you can achieve this even without creating custom control - just add these event handlers to standard TreeView