Export (0) Print
Expand All

TreeView.DrawNode Event

Occurs when a TreeView is drawn and the DrawMode property is set to a TreeViewDrawMode value other than Normal.

Namespace:  System.Windows.Forms
Assembly:  System.Windows.Forms (in System.Windows.Forms.dll)

public event DrawTreeNodeEventHandler DrawNode

Use this event to customize the appearance of nodes in a TreeView control using owner drawing.

This event is raised only when the DrawMode property is set to TreeViewDrawMode values of OwnerDrawAll or OwnerDrawText. The following table indicates how the TreeNode can be customized when the DrawMode property is set to these values.

DrawMode property value

TreeNode customization

OwnerDrawText

The TreeNode label area can be customized. All other TreeNode elements are drawn automatically.

OwnerDrawAll

The appearance of the entire TreeNode can be customized. Icons, check boxes, plus and minus signs, and lines connecting the nodes must be drawn manually if they are desired.

The region that the TreeNode.Text value would occupy if it were drawn using the font specified by the TreeView control's Font property is the region in which a node can be clicked to select it. This is called the hit test region. If you draw outside this region, you should provide your own code that selects a node when its visible area is clicked.

The hit test region corresponds to the DrawTreeNodeEventArgs.Bounds property when using OwnerDrawText. When using OwnerDrawAll, however, the DrawTreeNodeEventArgs.Bounds property encompasses the entire width of the TreeView. In this case, you can access the hit test region by getting the DrawTreeNodeEventArgs.Node value and accessing its TreeNode.Bounds property. You can then draw the hit test region of the node within these bounds, or you can provide your own hit test code. Note that setting the TreeNode.NodeFont property does not change the size of the hit test region, which is calculated using the font specified for the entire TreeView.

For more information about how to handle events, see Handling and Raising Events.

The following code example demonstrates how to customize a TreeView control using owner drawing. The TreeView control in the example displays optional node tags alongside the standard node labels. Node tags are specified by using the TreeNode.Tag property. The TreeView control also uses custom colors, which include a custom highlight color.

You can customize most of the TreeView colors by setting color properties, but the selection highlight color is not available as a property. Additionally, the default selection highlight rectangle extends only around a node label. Owner drawing must be used to draw the node tags and to draw a customized highlight rectangle large enough to include a node tag.

In the example, a handler for the DrawNode event draws the node tags and the custom selection highlight manually. Unselected nodes do not need customization. For these, the DrawTreeNodeEventArgs.DrawDefault property is set to true so that they will be drawn by the operating system.

Additionally, a handler for the MouseDown event provides hit-testing. By default, a node can be selected only by clicking the region around its label. The MouseDown event handler selects a node that is clicked anywhere within this region or within the region around a node tag, if present.

using System;
using System.Drawing;
using System.Windows.Forms;

public class TreeViewOwnerDraw : Form
{
    private TreeView myTreeView;

    // Create a Font object for the node tags.
    Font tagFont = new Font("Helvetica", 8, FontStyle.Bold);

    public TreeViewOwnerDraw()
    {
        // Create and initialize the TreeView control.
        myTreeView = new TreeView();
        myTreeView.Dock = DockStyle.Fill;
        myTreeView.BackColor = Color.Tan;
        myTreeView.CheckBoxes = true;

        // Add nodes to the TreeView control.
        TreeNode node;
        for (int x = 1; x < 4; ++x)
        {
            // Add a root node to the TreeView control.
            node = myTreeView.Nodes.Add(String.Format("Task {0}", x));
            for (int y = 1; y < 4; ++y)
            {
                // Add a child node to the root node.
                node.Nodes.Add(String.Format("Subtask {0}", y));
            }
        }
        myTreeView.ExpandAll();

        // Add tags containing alert messages to a few nodes  
        // and set the node background color to highlight them.
        myTreeView.Nodes[1].Nodes[0].Tag = "urgent!";
        myTreeView.Nodes[1].Nodes[0].BackColor = Color.Yellow;
        myTreeView.SelectedNode = myTreeView.Nodes[1].Nodes[0];
        myTreeView.Nodes[2].Nodes[1].Tag = "urgent!";
        myTreeView.Nodes[2].Nodes[1].BackColor = Color.Yellow;

        // Configure the TreeView control for owner-draw and add 
        // a handler for the DrawNode event.
        myTreeView.DrawMode = TreeViewDrawMode.OwnerDrawText;
        myTreeView.DrawNode += 
            new DrawTreeNodeEventHandler(myTreeView_DrawNode);

        // Add a handler for the MouseDown event so that a node can be  
        // selected by clicking the tag text as well as the node text.
        myTreeView.MouseDown += new MouseEventHandler(myTreeView_MouseDown);

        // Initialize the form and add the TreeView control to it. 
        this.ClientSize = new Size(292, 273);
        this.Controls.Add(myTreeView);
    }

    // Clean up any resources being used.         
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            tagFont.Dispose();
        }
        base.Dispose(disposing);
    }

    [STAThreadAttribute()]
    static void Main() 
    {
        Application.Run(new TreeViewOwnerDraw());
    }

    // Draws a node. 
    private void myTreeView_DrawNode(
        object sender, DrawTreeNodeEventArgs e)
    {
        // Draw the background and node text for a selected node. 
        if ((e.State & TreeNodeStates.Selected) != 0)
        {
            // Draw the background of the selected node. The NodeBounds 
            // method makes the highlight rectangle large enough to 
            // include the text of a node tag, if one is present.
            e.Graphics.FillRectangle(Brushes.Green, NodeBounds(e.Node));

            // Retrieve the node font. If the node font has not been set, 
            // use the TreeView font.
            Font nodeFont = e.Node.NodeFont;
            if (nodeFont == null) nodeFont = ((TreeView)sender).Font;

            // Draw the node text.
            e.Graphics.DrawString(e.Node.Text, nodeFont, Brushes.White,
                Rectangle.Inflate(e.Bounds, 2, 0));
        }

        // Use the default background and node text. 
        else 
        {
            e.DrawDefault = true;
        }

        // If a node tag is present, draw its string representation  
        // to the right of the label text. 
        if (e.Node.Tag != null)
        {
            e.Graphics.DrawString(e.Node.Tag.ToString(), tagFont,
                Brushes.Yellow, e.Bounds.Right + 2, e.Bounds.Top);
        }

        // If the node has focus, draw the focus rectangle large, making 
        // it large enough to include the text of the node tag, if present. 
        if ((e.State & TreeNodeStates.Focused) != 0)
        {
            using (Pen focusPen = new Pen(Color.Black))
            {
                focusPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                Rectangle focusBounds = NodeBounds(e.Node);
                focusBounds.Size = new Size(focusBounds.Width - 1, 
                focusBounds.Height - 1);
                e.Graphics.DrawRectangle(focusPen, focusBounds);
            }
        }
    }

    // Selects a node that is clicked on its label or tag text. 
    private void myTreeView_MouseDown(object sender, MouseEventArgs e)
    {
        TreeNode clickedNode = myTreeView.GetNodeAt(e.X, e.Y);
        if (NodeBounds(clickedNode).Contains(e.X, e.Y))
        {
            myTreeView.SelectedNode = clickedNode;
        }
    }

    // Returns the bounds of the specified node, including the region  
    // occupied by the node label and any node tag displayed. 
    private Rectangle NodeBounds(TreeNode node)
    {
        // Set the return value to the normal node bounds.
        Rectangle bounds = node.Bounds;
        if (node.Tag != null)
        {
            // Retrieve a Graphics object from the TreeView handle 
            // and use it to calculate the display width of the tag.
            Graphics g = myTreeView.CreateGraphics(); 
            int tagWidth = (int)g.MeasureString
                (node.Tag.ToString(), tagFont).Width + 6;

            // Adjust the node bounds using the calculated value.
            bounds.Offset(tagWidth/2, 0);
            bounds = Rectangle.Inflate(bounds, tagWidth/2, 0);
            g.Dispose();
         }

        return bounds;

    }

}

.NET Framework

Supported in: 4.5.2, 4.5.1, 4.5, 4, 3.5, 3.0, 2.0

.NET Framework Client Profile

Supported in: 4, 3.5 SP1

Windows 8.1, Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows 7, Windows Vista SP2, Windows Server 2008 (Server Core Role not supported), Windows Server 2008 R2 (Server Core Role supported with SP1 or later; Itanium not supported)

The .NET Framework does not support all versions of every platform. For a list of the supported versions, see .NET Framework System Requirements.

Show:
© 2014 Microsoft