Click here to Skip to main content
15,892,072 members
Articles / Desktop Programming / Windows Forms

Windows Vista Treeview

Rate me:
Please Sign up or sign in to vote.
2.64/5 (10 votes)
12 Feb 2008CPOL 49.4K   2.7K   36   7
A custom made TreeView with Windows Vista look.

Vista_TreeView.jpg

Introduction

This is a custom TreeView control which provides a Windows Vista look.

Background

The code is a combination of three different codes made by José Manuel Menéndez Poo, Xasthom, and Stephen J Whiteley. As most of the code is made by Stephen, his copyright messages have been left.

This code is a part of the SQLmail.org project, an Open Source project whose goal is to make a MySQL based mail client. All messages should be stored in a SQL database which will provide extremely fast search. As I would like to have Windows Vista look for the whole program, almost all controls are customized. In the SQLmail.org project, you can find a Vista customized button, a radio button, a checkbox, a toolstrip, and a datagrid, and the way to use them.

Using the Code

It is very easy to use this control. Download the class from the link at the top of the page and import it in your project. Build your project, and you will find it as a new control in the Toolbox.

You can use a custom node like this:

VB
Dim NewNode As New WindowsVistaNode
NewNode.Name = "myname"
NewNode.Text = "text"
' If you need an icon next to the node, add an ImageList
' on the form, import images in it (Images, Collection),
' on the treeview select the added ImageList in the ImageList property
NewNode.ImageKey = "image.gif" ' name of the image in the ImageList collection
NewNode.SelectedImageKey = "image.gif"
' name of the image which will be drawn when the node is selected, 
' for example, a closed folder for default and an open one for selected

'
' If you want to change a font on the specific node
NewNode.Font = New Font(TreeView1.Font.FontFamily, _
                        TreeView1.Font.Size, FontStyle.Bold)
' Title property is a custom property which allowes you
' to have different sections in a treeview.
' Title node cannot be selected, cannot be closed (always expanded),
' cannot be highlighted when the mouse is hovering
' and the text is always left alligned
NewNode.Title = True
NewNode.Text = UCase(NewNode.Text) ' use it for title nodes
'
Folder_Tree.Nodes.Add(NewNode)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Croatia Croatia
28 years of experience with computers, 8 with BASIC and Z80 assemblers (ZX Spectrum), 6 years VB, 6 years MS Office Macros, 1 year C#, 10 years MS SQL, 1 year MySQL, 5 years ASP and 3 years PHP. Playing with javascript in last couple of months.

Comments and Discussions

 
QuestionModified for TriState? Pin
Tim8w7-Jun-22 6:34
Tim8w7-Jun-22 6:34 
Questiondose it have C++ version ? Pin
haily_lee2-Nov-10 22:51
haily_lee2-Nov-10 22:51 
GeneralIf anyone wants, here is a C# version Pin
Nadeem031927-Sep-09 16:51
Nadeem031927-Sep-09 16:51 
<pre>
using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Globalization;

// -----------------------------------------------------------------------------
// Copyright © 2007 Stephen J Whiteley
//
// This source code is provided AS IS, with no warranty expressed or implied,
// including without limitation, warranties of merchantability or
// fitness for a particular purpose or any warranty of title or
// non-infringement. This disclaimer must be passed on whenever the Software
// is distributed in either source form or as a derivative works.
// It may be used for both commercial and non-commercial applications.
//
// -----------------------------------------------------------------------------

public class VistaTreeView : TreeView
{

      public VistaTreeView()
      {
            // ---------------------------------------------------------------------
            // New Treeview
            // ---------------------------------------------------------------------
            //
            base.LineColor = SystemColors.GrayText;
            _expanderStyle = TreeExpanderStyle.Arrow;

            this.BackColor = Color.FromArgb(232, 232, 232);
            LoadExpanderImages();
            //
            // Set the style to double buffered and do all the drawing in
            // the paint event (onPaint) of the treeview.
            //
            // This reduces the flicker, but is a lot more work
            //
            base.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
            base.UpdateStyles();
            // Update the styles
            //
            // Set the treeview styles
            SetTreeviewStyle();
      }

      #region "-   Enums   -"
      public enum TreeExpanderStyle
      {
            PlusMinus = 0,
            Arrow = 1
      }
      #endregion

      #region "-   Properties   -"

      #region "-   Private Variables   -"
      private string CollapsedString = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAARpJREFUOE+lk9tKAmEUhfWhfIiew1eyUkkvPCaNdZdHbPCACIqCklZERQZCZhNZeZylS5jRhvlHcAb2zcD61tqLfzsBOGx9BNgZXdwffCKYLCEgFXF2IcN3XoA3nsNJJAtPOK1Ptd5Z+21NdUDwsgxVBRZLFdPZEj9/CyjjOd6VKd6GEzwPfnH/OobryG0OCEilvWK58SIGMLbRmW6ac+fpG1fynRjgX+9sjE0AY1PcfPiCVLAAnMby+s4UGqfWVZDI98QJjqMZ08LoTHG5PUI82xUDPJH0v7YZmyk08U3rA9HMHsBuYbvOFOcaQ4RTt9YJWFix2Ueq8rgpjDszNp0pDl1bAPjCzMoz/hO+xEPvwdYhbS75UGdNtwLNm+LI5h1FwAAAAABJRU5ErkJggg==";
      private string CollapsedArrowString = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAANFJREFUOE+l00kKhDAQheHq+x/KlaALxXkeF04o4g1ep0J3Y0OEiILoIvnyK9QLAD26GHhyKzc7joNpmmhZFtq2jfZ9p+M4lGsvgTOyrqtEVKWXQN/3YGQcR1nCiDZg2zbatsUZmef5HlBVFZqmQdd1smQYBn3AsizkeY6yLP8Q7U8wTRNpmv4QLhAl+gUMRFGEJEnA76KE6rrWBwzDQBAE4KdAKMsyKoriHvBBSJTQF9H+B7zZdV3yPI9836cwDCmOY/2CO7PxaJDkJN85TbX2Db5d1YfJcQ3TAAAAAElFTkSuQmCC";
      private Image CollapsedIcon;
      private string ExpandedString = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAO9JREFUOE+lk9sKAVEUhnkoD+E5vJJzuHEshzs1DiGUQ0RRigsKJceRcWZ+tppxmjXKTK2bqe/791p7Lz0AnaaPCbSUDI8mK3iiBbgjebjCOThCGdiDKVh9SZi9nFylWvue9wyVBZ5YEaIIXK4ijqcrtvsLeOGMGX/EeH7AYLJDdyjAYDQpC9yRwk+43d/QAnZstWQGN3prWuC890wdW4IrHZ4W2AJpuWfW52cxuNha0gKLP/E1sNdkBmebC1pg9nFv01aCU/W5ukC6KgrmqjN1AbtnNThentIC9sKUhvf5j3yJ/+6DpkV6bPK/yRJ3A/PE7e2oP8DgAAAAAElFTkSuQmCCAPjCzMoz/hO+xEPvwdYhbS75UGdNtwLNm+LI5h1FwAAAAABJRU5ErkJggg==";
      private string ExpandedArrowString = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAM9JREFUOE/N0kkKg0AQBdCf+x/KlaALxXkeF04o4g0qXU1sDPQqBhLhI72o17+gH0SEWx8Dd3JrWLa/c/t3Ac/ziOM4Dtm2LWNZFpmmKWMYhsq1tVphmiYw0Pc9tW1LVVVRnueUpilFUURBEEjAdd23tdVhWRZckaZpqCxLiSRJIocFwpfogW3bwMg4juDqXdfRifCwQCCawPd9PbDvO9Z1VQgPMcJ/0QRZloGRMAz1wHEcOJF5njEMA14I6rpGURQSieNYD3z6Hv7oIf1shSf3G9UMQ+Vu/QAAAABJRU5ErkJggg==";
      private Image ExpandedIcon;
      //
      // Text Formatting
      private StringFormat TextFormat = new StringFormat(StringFormatFlags.NoWrap);
      //
      private Pen HighlightBorderPen = new Pen(Color.FromArgb(255, 127, 157, 185));
      private Color HighlightColor = Color.FromArgb(255, 204, 230, 255);
      private SolidBrush HighlightBrush = new SolidBrush(Color.FromArgb(255, 204, 230, 255));
      private Color RootColor = Color.FromArgb(255, 204, 204, 204);
      //
      private bool _haveImages;
      private TreeExpanderStyle _expanderStyle;
      private Image _backgroundimage;
      private string _lastKnowTopIndex = "";
      //
      private Brush NodeBrush;
      #endregion

      #region "-   Appearance   -"

      private Color mBaseColor = Color.FromArgb(0, 5, 10);
      // The backing color that the rest of
      // the Checkbox is drawn. For a glassier
      // effect set this property to Transparent.
      [Category("Appearance"), DefaultValue(typeof(Color), "110, 115, 110"), Description("The backing color that the rest of the highlighted area is drawn. For a glassier effect set this property to Transparent.")]
      public Color NodeBaseColor
      {
            get { return mBaseColor; }
            set
            {
                  mBaseColor = value;
                  this.Invalidate();
            }
      }

      private Color mNodeColor = Color.FromArgb(0, 0, 32);
      // The bottom color of the Checkbox that
      // will be drawn over the base color.
      [Category("Appearance"), DefaultValue(typeof(Color), "200, 200, 232"), Description("The bottom color of the highlighted node that will be drawn over the base color.")]
      public Color NodeColor
      {
            get { return mNodeColor; }
            set
            {
                  mNodeColor = value;
                  this.Invalidate();
            }
      }

      private Color mSelectedColor = Color.White;
      // The font color of a selected node.
      [Category("Appearance"), DefaultValue(typeof(Color), "White"), Description("The font color of a selected node.")]
      public Color FontColorSelected
      {
            get { return mSelectedColor; }
            set
            {
                  mSelectedColor = value;
                  this.Invalidate();
            }
      }

      private Color mHotTrackingColor = Color.Silver;
      // The font color of a hovered node if the hottracking is on.
      [Category("Appearance"), DefaultValue(typeof(Color), "Silver"), Description("The font color of a hovered node if the hottracking is on.")]
      public Color FontColorHotTracking
      {
            get { return mHotTrackingColor; }
            set
            {
                  mHotTrackingColor = value;
                  this.Invalidate();
            }
      }

      private Font mFontHotTracking = new Font("Arial", 10);
      // The hovered node font if the hottracking is on.
      [Category("Appearance"), Description("The hovered node font if the hottracking is on.")]
      public Font FontHotTracking
      {
            get { return mFontHotTracking; }
            set
            {
                  mFontHotTracking = value;
                  this.Invalidate();
            }
      }

      #endregion

      #region "-   Behavior   -"
      [Category("Behavior"), DefaultValue(typeof(TreeExpanderStyle), "Arrow"), Description("Collapsing arrow style.")]
      public TreeExpanderStyle ExpanderStyle
      {
            get { return _expanderStyle; }
            set
            {
                  if (_expanderStyle != value)
                  {
                        _expanderStyle = value;
                        // Load the expander styles and redraw
                        // the whole treeview
                        LoadExpanderImages();
                        base.Invalidate();
                  }
            }
      }

      #endregion

      #region "-   Image   -"
      // The background image
      [Category("Image"), DefaultValue(typeof(Image), null), Description("The image displayed on the treeview background."), EditorBrowsable(EditorBrowsableState.Always), Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Bindable(true)]
      public override Image BackgroundImage
      {
            get { return _backgroundimage; }
            set
            {
                  _backgroundimage = value;
                  this.Invalidate();
            }
      }
      #endregion

      #region "-   Shadowed properties   -"

      public new ImageList ImageList
      {
            get { return base.ImageList; }
            set
            {
                  base.ImageList = value;
                  _haveImages = (base.ImageList != null);
            }
      }

      [Browsable(true), ReadOnly(false)]
      public new Font Font
      {
            get { return base.Font; }
            set
            {
                  base.Font = value;
                  SetTreeviewStyle();
            }
      }

      [Browsable(false), ReadOnly(true)]
      public new TreeViewDrawMode DrawMode
      {
            get { return base.DrawMode; }
      }

      [Browsable(false), ReadOnly(true)]
      public new bool ShowLines
      {
            get { return base.ShowLines; }
      }

      [Browsable(false), ReadOnly(true)]
      public new bool ShowRootLines
      {
            get { return base.ShowRootLines; }
      }

      [Browsable(false), ReadOnly(true)]
      public new bool LabelEdit
      {
            get { return base.LabelEdit; }
      }

      [Browsable(false), ReadOnly(true)]
      public new bool ShowPlusMinus
      {
            get { return base.ShowPlusMinus; }
      }

      [Browsable(false), ReadOnly(true)]
      public new Color LineColor
      {
            get { return base.LineColor; }
      }

      [Browsable(false), ReadOnly(true)]
      public new bool CheckBoxes
      {
            get { return base.CheckBoxes; }
      }

      #endregion

      #endregion

      #region "-   Overrided subs   -"
      protected override void InitLayout()
      {
            // ---------------------------------------------------------------------
            // New Treeview: Initialize the Layout
            // ---------------------------------------------------------------------
            base.InitLayout();
            //
            // Overridden properties
            base.DrawMode = TreeViewDrawMode.OwnerDrawAll;
            base.ShowPlusMinus = true;
            base.ShowLines = false;
            base.ShowRootLines = true;
            base.CheckBoxes = false;
            //'
            base.LineColor = Color.Black;
      }
      protected override void OnAfterCollapse(System.Windows.Forms.TreeViewEventArgs e)
      {
            // ---------------------------------------------------------------------
            // After collapsing - redo the node count
            // ---------------------------------------------------------------------
            base.OnAfterCollapse(e);
      }

      protected override void OnAfterExpand(System.Windows.Forms.TreeViewEventArgs e)
      {
            // ---------------------------------------------------------------------
            // After Expanding - redo the node count
            // ---------------------------------------------------------------------
            base.OnAfterExpand(e);
      }

      protected override void OnParentFontChanged(System.EventArgs e)
      {
            // ---------------------------------------------------------------------
            // Override the OnParentFontChanged event
            // ---------------------------------------------------------------------
            base.OnParentFontChanged(e);
            SetTreeviewStyle();
      }

      protected override void OnBeforeSelect(System.Windows.Forms.TreeViewCancelEventArgs e)
      {
            // ---------------------------------------------------------------------
            // Override the OnBeforeSelect event
            // ---------------------------------------------------------------------
            base.OnBeforeSelect(e);
            try
            {
                  VistaNode _node = (VistaNode)e.Node;
                  if (_node.Title) e.Cancel = true;
            }
            catch (Exception ex)
            {
            }
      }

      protected override void OnBeforeExpand(System.Windows.Forms.TreeViewCancelEventArgs e)
      {
            // ---------------------------------------------------------------------
            // Override the OnBeforeExpand event
            // ---------------------------------------------------------------------
            base.OnBeforeExpand(e);
            base.Invalidate();
      }

      protected override void OnBeforeCollapse(System.Windows.Forms.TreeViewCancelEventArgs e)
      {
            // ---------------------------------------------------------------------
            // Override the OnBeforeCollapse event
            // ---------------------------------------------------------------------
            try
            {
                  VistaNode _node = (VistaNode)e.Node;
                  if (_node.Title) e.Cancel = true;
            }
            catch (Exception ex)
            {
            }

            base.OnBeforeCollapse(e);
            base.Invalidate();
      }
      protected override void OnPaintBackground(System.Windows.Forms.PaintEventArgs pevent)
      {
            // ---------------------------------------------------------------------
            // Override the OnPaintBackground event
            // ---------------------------------------------------------------------
            if (_backgroundimage != null)
            {
                  pevent.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
                  pevent.Graphics.DrawImage(_backgroundimage, new Rectangle(0, 0, this.Width, this.Height));
            }
            else
            {
                  LinearGradientBrush b = new LinearGradientBrush(Point.Empty, new PointF(0, this.Height), Color.Black, this.BackColor);
                  GraphicsPath border = new GraphicsPath();
                  pevent.Graphics.FillRectangle(b, new Rectangle(0, 0, this.Width - 1, this.Height - 1));
                  Int32 glowSize = Convert.ToInt32(Convert.ToSingle(this.Height) / 2);
                  Rectangle glow = new Rectangle(0, this.Height - glowSize - 1, this.Width - 1, glowSize);
                  b = new LinearGradientBrush(new Point(0, glow.Top - 1), new PointF(0, glow.Bottom), Color.FromArgb(0, Color.FromArgb(0x43, 0x53, 0x7a)), Color.FromArgb(0x43, 0x53, 0x7a));
                  pevent.Graphics.FillRectangle(b, glow);
            }
            // If scroll, draw it again
            if (this.TopNode != null)
            {
                  if (_lastKnowTopIndex != this.TopNode.Name)
                  {
                        this.Invalidate();
                        _lastKnowTopIndex = this.TopNode.Name;
                  }
            }
      }

      protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
      {
            // ---------------------------------------------------------------------
            // Override the OnPaint event to paint the nodes
            // ---------------------------------------------------------------------
            //            MyBase.OnPaint(e)
            PaintNodes(base.Nodes, e);
      }

      #endregion

      #region "-   Private subs   -"
      private void LoadExpanderImages()
      {
            // ---------------------------------------------------------------------
            // Loads the included and defined expander images
            // ---------------------------------------------------------------------
            //
            byte[] b = null;
            //
            // Expanded Image
            switch (_expanderStyle)
            {
                  case TreeExpanderStyle.Arrow:
                        b = Convert.FromBase64String(ExpandedArrowString);
                        break;
                  default:
                        b = Convert.FromBase64String(ExpandedString);
                        break;
            }
            System.IO.MemoryStream ms = new System.IO.MemoryStream();
            ms.Write(b, 0, b.Length);
            ExpandedIcon = Image.FromStream(ms);
            //
            // Collapsed Image
            switch (_expanderStyle)
            {
                  case TreeExpanderStyle.Arrow:
                        b = Convert.FromBase64String(CollapsedArrowString);
                        break;
                  default:
                        b = Convert.FromBase64String(CollapsedString);
                        break;
            }
            ms.Position = 0;
            ms.Write(b, 0, b.Length);
            CollapsedIcon = Image.FromStream(ms);
            //'
            ms.Close();
      }
      private void SetTreeviewStyle()
      {
            // ---------------------------------------------------------------------
            // Sets the various Treeview settings
            // ---------------------------------------------------------------------
            //
            // Unselect the node if it's a parent and are not allowed
            // to select parent nodes
            //
            // ensure a node is selected
            if (base.SelectedNode == null)
            {
                  foreach (TreeNode n in base.Nodes)
                  {
                        base.SelectedNode = n;
                        break; // TODO: might not be correct. Was : Exit For
                  }
            }
            //
            Graphics g = this.CreateGraphics();
            SizeF sz = g.MeasureString(CollapsedString.Substring(0, 2), this.Font, 125);
            int newHeight = Convert.ToInt32(Math.Ceiling(sz.Height));
            if (newHeight &gt; base.ItemHeight) base.ItemHeight = newHeight;
            g.Dispose();
            //
            //'
            NodeBrush = new SolidBrush(this.ForeColor);
      }
      #endregion

      #region "-   Drawing   -"
      private void PaintNodes(TreeNodeCollection parentNodes, PaintEventArgs args)
      {
            // ---------------------------------------------------------------------
            // Paint the nodes
            // ---------------------------------------------------------------------
            //
            // Hottracking - find a node over which is the mouse
            VistaNode on_item = null;
            if (this.HotTracking)
            {
                  Point LocalMousePosition = default(Point);
                  LocalMousePosition = this.PointToClient(Cursor.Position);
                  on_item = (VistaNode)this.GetNodeAt(LocalMousePosition);
                  if (on_item != null)
                  {
                        if (on_item.Title) on_item = null;
                  }
            }

            foreach (TreeNode n in parentNodes)
            {
                  Rectangle b = new Rectangle(0, n.Bounds.Y, base.ClientSize.Width, n.Bounds.Height);
                  if (args.ClipRectangle.IntersectsWith(b))
                  {
                        // This node intersects with the clip rectangle, so draw it
                        b = new Rectangle(n.Bounds.X, n.Bounds.Y, base.ClientSize.Width - n.Bounds.X - 1, n.Bounds.Height);
                        DrawThisNode(args.Graphics, n, b, object.ReferenceEquals(n, on_item));
                  }
                  // Check for children nodes
                  // (Recursively draw the nodes)
                  if (n.Nodes.Count &gt; 0) PaintNodes(n.Nodes, args);
            }
      }

      private void DrawThisNode(Graphics g, TreeNode node, Rectangle rBounds, bool HotTracked)
      {
            // ---------------------------------------------------------------------
            // Draw a specific node
            // ---------------------------------------------------------------------
            //
            bool selected = node.IsSelected;
            // convenience
            //
            bool hasExpander = false;
            // has an Expand/collaps been drawn for this node
            Size imageSize = default(Size);
            // has an image been drawn for this node
            //
            //
            // Draw selected node background
            if (selected) DrawNodeBackground(g, new Rectangle(-2, rBounds.Y, base.Width + 2, rBounds.Height));
            //
            // Draw expander and image
            Rectangle expRect = new Rectangle(rBounds.X - 17, rBounds.Y, rBounds.Width + 12, rBounds.Height);
            if (base.ImageList != null)
            {
                  switch (base.ImageList.ImageSize.Width)
                  {
                        case 1: // TODO: to 16
                              expRect = new Rectangle(rBounds.X - base.ImageList.ImageSize.Width - 20, rBounds.Y, rBounds.Width + base.ImageList.ImageSize.Width + 3, rBounds.Height);
                              break;
                        case   // ERROR: Case labels with binary operators are unsupported : GreaterThan
16:
                              expRect = new Rectangle(rBounds.X - 2 * base.ImageList.ImageSize.Width - 4, rBounds.Y, rBounds.Width + 2 * base.ImageList.ImageSize.Width - 13, rBounds.Height);
                              break;
                  }
            }
            hasExpander = DrawNodeExpander(g, node, expRect);
            imageSize = DrawNodeImage(g, node, new Rectangle(expRect.X + 22, rBounds.Y, expRect.Width - 17, rBounds.Height));
            //
            //
            // Reduce the SIZE of the bounds, used for drawing rectangles
            Rectangle rBorder = new Rectangle(expRect.X + imageSize.Width + 22, rBounds.Y, expRect.Width - imageSize.Width - 17 + rBounds.X, rBounds.Height - 1);
            //
            // Draw the actual Text
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            RectangleF rText = DrawNodeText(g, node, rBorder, selected, HotTracked);
            // Draw any node customization
            //'
            DrawNodeCustom(g, node, rText);
      }

      private Size DrawNodeImage(Graphics g, TreeNode node, Rectangle r)
      {
            // ---------------------------------------------------------------------
            // Draw the IMAGE associated with this node
            // ---------------------------------------------------------------------
            if (_haveImages == false) return new Size(0, 0);

            VistaNode n = node as VistaNode;
            if (n != null)
            {
                  // No images for titles - this code should be changed, but the drawing text code has to be changed as well
                  if (n.Title) return new Size(0, 0);
            }
            // Have images: does this NODE have an image?
            //
            Image img = null;
            // Define an image object
            //
            if (node.IsSelected)
            {
                  // SELECTED
                  if (node.SelectedImageIndex &gt;= 0)
                  {
                        img = base.ImageList.Images[node.SelectedImageIndex];
                  }
                  else if (node.SelectedImageKey != null)
                  {
                        img = base.ImageList.Images[node.SelectedImageKey];
                  }
            }
            else
            {
                  // NOT SELECTED
                  if (node.ImageIndex &gt;= 0)
                  {
                        img = base.ImageList.Images[node.ImageIndex];
                  }
                  else if (node.ImageKey != null)
                  {
                        img = base.ImageList.Images[node.ImageKey];
                  }
            }
            if (img == null) return new Size(0, 0);
            // If an image exists, then draw this image at the correct position
            Int32 yPosition = r.Y + (base.ItemHeight - img.Height) / 2;
            g.DrawImage(img, r.X, yPosition);
            // move the text 8px to the right of the image
            return new Size(img.Width + 8, img.Height);
      }

      private bool DrawNodeExpander(Graphics g, TreeNode node, Rectangle r)
      {
            // ---------------------------------------------------------------------
            // Draw the Expander, returning T/F for expander drawn
            // ---------------------------------------------------------------------
            // Draw the PLUS/MINUS Expand/Collapse Icon if necessary
            //If (node.Level = 0 And _collapsibleParent = False) Then Return False
            // Set the position for the Expand/collapse icon
            bool result = false;
            VistaNode n = node as VistaNode;
            if (n != null)
            {
                  if (n.Title) return result;
            }

            if (node.IsExpanded)
            {
                  // Draw the EXPANDED Icon
                  Int32 yPosition = r.Y + (base.ItemHeight - ExpandedIcon.Height) / 2;
                  g.DrawImage(ExpandedIcon, r.X, yPosition);
                  result = true;
            }
            else
            {
                  if (node.Nodes.Count &gt; 0)
                  {
                        // Draw the Collapsed Icon
                        Int32 yPosition = r.Y + (base.ItemHeight - CollapsedIcon.Height) / 2;
                        g.DrawImage(CollapsedIcon, r.X, yPosition);
                        result = true;
                  }
            }
            // Has an expander been drawn
            return result;
      }

      private void DrawNodeBackground(Graphics g, Rectangle rBorder)
      {
            // ---------------------------------------------------------------------
            // Draws the background for a Node
            // ---------------------------------------------------------------------
            DrawBackground(g, rBorder);
            DrawOuterStroke(g, rBorder);
            DrawInnerStroke(g, rBorder);
            DrawHighlight(g, rBorder);
            DrawGlossyEffect(g, rBorder);
      }

      private void DrawBackground(Graphics g, Rectangle r)
      {
            Int32 alpha = 127;
            SolidBrush sb = new SolidBrush(this.NodeBaseColor);
            g.FillRectangle(sb, r);
            SetClip(g);
            g.ResetClip();
            sb = new SolidBrush(Color.FromArgb(alpha, this.NodeColor));
            g.FillRectangle(sb, r);
      }

      private void DrawOuterStroke(Graphics g, Rectangle r)
      {
            Pen p = new Pen(this.NodeColor);
            g.DrawLine(p, r.Left, r.Top, r.Right - 1, r.Top);
            g.DrawLine(p, r.Left, r.Bottom - 1, r.Right - 1, r.Bottom - 1);
      }

      private void DrawInnerStroke(Graphics g, Rectangle r)
      {
            r.X += 1;
            r.Y += 1;
            r.Width -= 2;
            r.Height -= 2;
            Pen p = new Pen(this.HighlightColor);
            g.DrawLine(p, r.Left, r.Top, r.Right - 1, r.Top);
            g.DrawLine(p, r.Left, r.Bottom - 1, r.Right - 1, r.Bottom - 1);
      }

      private void DrawHighlight(Graphics g, Rectangle rBorder)
      {
            if (!this.Enabled) return;
            Int32 alpha = 150;
            Rectangle r = new Rectangle(rBorder.X, rBorder.Y, rBorder.Width, rBorder.Height / 2);
            LinearGradientBrush lg = new LinearGradientBrush(r, Color.FromArgb(alpha, this.HighlightColor), Color.FromArgb(alpha / 3, this.HighlightColor), 90.1f, true);
            lg.WrapMode = WrapMode.TileFlipXY;
            g.FillRectangle(lg, r);
      }
      private void DrawGlossyEffect(Graphics g, Rectangle rBorder)
      {
            SetClip(g);
            Rectangle r = new Rectangle(rBorder.X, rBorder.Y, rBorder.Width, rBorder.Height);
            GraphicsPath glow = CreateTopRoundRectangle(r, 2);
            PathGradientBrush gl = new PathGradientBrush(glow);
            gl.CenterColor = Color.FromArgb(70, Color.FromArgb(141, 189, 255));
            gl.SurroundColors = new Color[] { Color.FromArgb(0, Color.FromArgb(141, 189, 255)) };
            g.FillPath(gl, glow);
            g.ResetClip();
      }

      private void SetClip(Graphics g)
      {
            Rectangle r = this.ClientRectangle;
            r.X += 1;
            r.Y += 1;
            r.Width -= 3;
            r.Height -= 3;
            g.SetClip(r);
      }

      private RectangleF DrawNodeText(Graphics g, TreeNode node, Rectangle rBounds, bool selected, bool HotTracked)
      {
            // ---------------------------------------------------------------------
            // Draw the actual node text
            // Returns a rectangle where the text was drawn
            // ---------------------------------------------------------------------
            string txt = node.Text;
            bool title = false;
            Font NodeFont = default(Font);
            if (HotTracked &amp; !selected)
            {
                  NodeFont = this.FontHotTracking;
                  NodeBrush = new SolidBrush(this.FontColorHotTracking);
            }
            else if (selected)
            {
                  NodeFont = this.Font;
                  NodeBrush = new SolidBrush(this.FontColorSelected);
            }
            else
            {
                  NodeFont = this.Font;
                  if (node.ForeColor.IsEmpty)
                  {
                        NodeBrush = new SolidBrush(this.ForeColor);
                  }
                  else
                  {
                        NodeBrush = new SolidBrush(node.ForeColor);
                  }
            }
            VistaNode n = node as VistaNode;
            if (n != null)
            {
                  if (n.NodeFont != null) NodeFont = n.NodeFont;
                  if (n.Highlighted)
                  {
                        NodeBrush = new SolidBrush(n.HighlightedColor);
                        NodeFont = new Font(NodeFont.FontFamily, NodeFont.Size, FontStyle.Bold);
                  }
                  title = n.Title;
            }

            SizeF sz = g.MeasureString(txt, NodeFont, rBounds.Width, TextFormat);
            RectangleF textBounds = default(RectangleF);
            if (title)
            {
                  textBounds = new RectangleF(10, rBounds.Y + Convert.ToInt32((rBounds.Height - sz.Height) / 2), rBounds.Width, Convert.ToInt32(sz.Height));
            }
            else
            {
                  textBounds = new RectangleF(rBounds.X, rBounds.Y + Convert.ToInt32((rBounds.Height - sz.Height) / 2), rBounds.Width, Convert.ToInt32(sz.Height));
            }
            g.DrawString(node.Text, NodeFont, NodeBrush, textBounds, TextFormat);
            // Return the rectanglewhere the text was drawn
            textBounds.Width = sz.Width;
            return textBounds;
      }

      private void DrawNodeCustom(Graphics g, TreeNode node, RectangleF rText)
      {
            // ---------------------------------------------------------------------
            // Draw a CUSTOM Node if it's been supplied
            // ---------------------------------------------------------------------
            VistaNode n = node as VistaNode;
            if (n == null) return;
            // Nothing is customized
            //
            // Draw the CUSTOM Properties for this node
            Brush br = default(Brush);
            // Get the Post-text color
            Color col = n.PostTextColor;
            // If there isn't a color, use the derault color
            Font NodeFont = default(Font);
            if (n.Font == null) NodeFont = this.Font; else NodeFont = n.Font;
            if (col.IsEmpty)
            {
                  br = NodeBrush;
            }
            else
            {
                  br = new SolidBrush(n.PostTextColor);
            }
            if (n.Highlighted)
            {
                  br = new SolidBrush(n.HighlightedColor);
                  NodeFont = new Font(this.Font.FontFamily, this.Font.Size, FontStyle.Bold);
            }
            g.DrawString(string.Format(CultureInfo.CurrentUICulture, " {0}", n.PostText), NodeFont, br, rText.X + rText.Width, rText.Y);
      }

      public GraphicsPath RoundRect(RectangleF r, float r1, float r2, float r3, float r4)
      {
            float x = r.X;
            float y = r.Y;
            float w = r.Width;
            float h = r.Height;
            GraphicsPath rr = new GraphicsPath();
            rr.AddBezier(x, y + r1, x, y, x + r1, y, x + r1, y);
            rr.AddLine(x + r1, y, x + w - r2, y);
            rr.AddBezier(x + w - r2, y, x + w, y, x + w, y + r2, x + w, y + r2);
            rr.AddLine(x + w, y + r2, x + w, y + h - r3);
            rr.AddBezier(x + w, y + h - r3, x + w, y + h, x + w - r3, y + h, x + w - r3, y + h);
            rr.AddLine(x + w - r3, y + h, x + r4, y + h);
            rr.AddBezier(x + r4, y + h, x, y + h, x, y + h - r4, x, y + h - r4);
            rr.AddLine(x, y + h - r4, x, y + r1);
            return rr;
      }

      #endregion

      #region "-   private functions   -"
      // Creates a rectangle rounded on the top
      // &lt;param name="rectangle"&gt;Base rectangle&lt;/param&gt;
      // &lt;param name="radius"&gt;Radius of the top corners&lt;/param&gt;
      // &lt;returns&gt;Rounded rectangle (on top) as a GraphicsPath object&lt;/returns&gt;
      private GraphicsPath CreateTopRoundRectangle(Rectangle rectangle, Int32 radius)
      {
            GraphicsPath path = new GraphicsPath();

            Int32 l = rectangle.Left;
            Int32 t = rectangle.Top;
            Int32 w = rectangle.Width;
            Int32 h = rectangle.Height;
            Int32 d = radius &lt;&lt; 1;

            path.AddArc(l, t, d, d, 180, 90);
            // topleft
            path.AddLine(l + radius, t, l + w - radius, t);
            // top
            path.AddArc(l + w - d, t, d, d, 270, 90);
            // topright
            path.AddLine(l + w, t + radius, l + w, t + h);
            // right
            path.AddLine(l + w, t + h, l, t + h);
            // bottom
            path.AddLine(l, t + h, l, t + radius);
            // left
            path.CloseFigure();

            return path;
      }

      #endregion
}

[Serializable()]
public class VistaNode : TreeNode
{

      private string _postText;
      private Color _postTextColor;
      private bool _postTextShow;
      private Font _font;
      private bool _highlighted;
      private Color _highlightedColor;
      private bool _title;

      // ---------------------------------------------------------------------
      // Constructor for Serialization
      // ---------------------------------------------------------------------
      protected VistaNode(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
            : base(info, context)
      {
      }

      public VistaNode()
      {
            _postTextColor = Color.Empty;
            _postTextShow = true;
            _postText = string.Empty;
            _font = null;
            _highlighted = false;
            _highlightedColor = Color.Empty;
            _title = false;
      }

      public string PostText
      {
            get { return _postText; }
            set
            {
                  _postText = value;
                  ForceUpdate();
            }
      }

      public Color PostTextColor
      {
            get { return _postTextColor; }
            set
            {
                  _postTextColor = value;
                  ForceUpdate();
            }
      }

      public Font Font
      {
            get { return _font; }
            set
            {
                  _font = value;
                  ForceUpdate();
            }
      }

      public Color HighlightedColor
      {
            get { return _highlightedColor; }
            set
            {
                  _highlightedColor = value;
                  ForceUpdate();
            }
      }

      public bool Highlighted
      {
            get { return _highlighted; }
            set
            {
                  _highlighted = value;
                  ForceUpdate();
            }
      }

      public bool PostTextShow
      {
            get { return _postTextShow; }
            set
            {
                  _postTextShow = value;
                  ForceUpdate();
            }
      }

      public bool Title
      {
            get { return _title; }
            set { _title = value; }
      }

      private void ForceUpdate()
      {
            // ---------------------------------------------------------------------
            // Force a change in the node text to update the
            // node in the parent treeview
            // Rather crude, but appears to work
            // ---------------------------------------------------------------------
            base.Text = base.Text;
      }
}
</pre>
GeneralRe: If anyone wants, here is a C# version Pin
Member 432946918-Jan-10 21:15
Member 432946918-Jan-10 21:15 
GeneralYou fixed the paint issue - well done! Pin
Scott Kane29-Jan-09 2:54
Scott Kane29-Jan-09 2:54 
GeneralRe: You fixed the paint issue - well done! Pin
Member 432946919-Jan-10 12:49
Member 432946919-Jan-10 12:49 
GeneralMy vote of 1 Pin
Member 46377011-Dec-08 8:20
Member 46377011-Dec-08 8:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.