Imports System.ComponentModel
' -----------------------------------------------------------------------------
' 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.
'
' -----------------------------------------------------------------------------
' Notes:
' Properties Added:
' ExpanderStyle
' ShadedParentStyle
' CollapsibleParent
' SelectableParent
'
' Properties/methods Removed/Readonly:
' DrawMode
' FullRowSelect
' ShowRootLines
' ShowLines
' LineColor
' LabelEdit
' ShowPlusMinus
' Checkboxes
'
' Shadowed:
' ImageList
' Font
'
' Custom node can be used as a node: contains a 'post text' property
' which is text which is drawn after the main text.
'
' Bugs:
' The horizontal scroll bar does not work correctly when 'posttext' is
' added to a node
'
' -----------------------------------------------------------------------------
' Version:
' -----------------------------------------------------------------------------
' 1.0 2007-02-17 SJW
' Initial Release
' 1.1 2007-04-11 TCA
' Modified to add background image
'
' -----------------------------------------------------------------------------
Public Class Tree : Inherits TreeView
Public Enum TreeExpanderStyle
PlusMinus = 0
Arrow = 1
End Enum
Private CollapsedString As String = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAARpJREFUOE+lk9tKAmEUhfWhfIiew1eyUkkvPCaNdZdHbPCACIqCklZERQZCZhNZeZylS5jRhvlHcAb2zcD61tqLfzsBOGx9BNgZXdwffCKYLCEgFXF2IcN3XoA3nsNJJAtPOK1Ptd5Z+21NdUDwsgxVBRZLFdPZEj9/CyjjOd6VKd6GEzwPfnH/OobryG0OCEilvWK58SIGMLbRmW6ac+fpG1fynRjgX+9sjE0AY1PcfPiCVLAAnMby+s4UGqfWVZDI98QJjqMZ08LoTHG5PUI82xUDPJH0v7YZmyk08U3rA9HMHsBuYbvOFOcaQ4RTt9YJWFix2Ueq8rgpjDszNp0pDl1bAPjCzMoz/hO+xEPvwdYhbS75UGdNtwLNm+LI5h1FwAAAAABJRU5ErkJggg=="
Private CollapsedArrowString As String = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAANFJREFUOE+l00kKhDAQheHq+x/KlaALxXkeF04o4g1ep0J3Y0OEiILoIvnyK9QLAD26GHhyKzc7joNpmmhZFtq2jfZ9p+M4lGsvgTOyrqtEVKWXQN/3YGQcR1nCiDZg2zbatsUZmef5HlBVFZqmQdd1smQYBn3AsizkeY6yLP8Q7U8wTRNpmv4QLhAl+gUMRFGEJEnA76KE6rrWBwzDQBAE4KdAKMsyKoriHvBBSJTQF9H+B7zZdV3yPI9836cwDCmOY/2CO7PxaJDkJN85TbX2Db5d1YfJcQ3TAAAAAElFTkSuQmCC"
Private CollapsedIcon As Image
Private ExpandedString As String = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAO9JREFUOE+lk9sKAVEUhnkoD+E5vJJzuHEshzs1DiGUQ0RRigsKJceRcWZ+tppxmjXKTK2bqe/791p7Lz0AnaaPCbSUDI8mK3iiBbgjebjCOThCGdiDKVh9SZi9nFylWvue9wyVBZ5YEaIIXK4ijqcrtvsLeOGMGX/EeH7AYLJDdyjAYDQpC9yRwk+43d/QAnZstWQGN3prWuC890wdW4IrHZ4W2AJpuWfW52cxuNha0gKLP/E1sNdkBmebC1pg9nFv01aCU/W5ukC6KgrmqjN1AbtnNThentIC9sKUhvf5j3yJ/+6DpkV6bPK/yRJ3A/PE7e2oP8DgAAAAAElFTkSuQmCCAPjCzMoz/hO+xEPvwdYhbS75UGdNtwLNm+LI5h1FwAAAAABJRU5ErkJggg=="
Private ExpandedArrowString As String = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAM9JREFUOE/N0kkKg0AQBdCf+x/KlaALxXkeF04o4g0qXU1sDPQqBhLhI72o17+gH0SEWx8Dd3JrWLa/c/t3Ac/ziOM4Dtm2LWNZFpmmKWMYhsq1tVphmiYw0Pc9tW1LVVVRnueUpilFUURBEEjAdd23tdVhWRZckaZpqCxLiSRJIocFwpfogW3bwMg4juDqXdfRifCwQCCawPd9PbDvO9Z1VQgPMcJ/0QRZloGRMAz1wHEcOJF5njEMA14I6rpGURQSieNYD3z6Hv7oIf1shSf3G9UMQ+Vu/QAAAABJRU5ErkJggg=="
Private ExpandedIcon As Image
'
Private Const ICON_SIZE As Integer = 16 ' All Icons are this size
Private Const EXPANDER_LOCATION As Integer = 18 ' Position to draw the expand/collapse
Private Const ICON_START As Integer = 19 ' Position that the TEXT is drawn for a node
' Text Formatting
Private TextFormat As New StringFormat(StringFormatFlags.NoWrap)
'
Private HighlightBorderPen As New Pen(Color.FromArgb(255, 127, 157, 185))
Private HighlightColor As Color = Color.FromArgb(255, 204, 230, 255)
Private HighlightBrush As New SolidBrush(HighlightColor)
Private RootColor As Color = Color.FromArgb(255, 204, 204, 204)
'
Private _collapsibleParent As Boolean
Private _selectableParent As Boolean
Private _parentShaded As Boolean
Private _haveImages As Boolean
Private _expanderStyle As TreeExpanderStyle
Private _nodeCount As Integer
'
' Fonts so we dn't have to create them each and every time
Private NodeBrush As Brush
Sub New()
' ---------------------------------------------------------------------
' New Treeview
' ---------------------------------------------------------------------
'
MyBase.LineColor = SystemColors.GrayText
_expanderStyle = TreeExpanderStyle.PlusMinus
Call 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
'
MyBase.SetStyle(ControlStyles.DoubleBuffer _
Or ControlStyles.UserPaint _
Or ControlStyles.AllPaintingInWmPaint, _
True)
MyBase.UpdateStyles() ' Update the styles
'
' Set the treeview styles
Call SetTreeviewStyle()
End Sub
Private Sub LoadExpanderImages()
' ---------------------------------------------------------------------
' Loads the included and defined expander images
' ---------------------------------------------------------------------
'
Dim b() As Byte
'
' Expanded Image
Select Case _expanderStyle
Case TreeExpanderStyle.Arrow
b = Convert.FromBase64String(ExpandedArrowString)
Case Else
b = Convert.FromBase64String(ExpandedString)
End Select
Dim ms As New System.IO.MemoryStream()
ms.Write(b, 0, b.Length)
ExpandedIcon = Image.FromStream(ms)
'
' Collapsed Image
Select Case _expanderStyle
Case TreeExpanderStyle.Arrow
b = Convert.FromBase64String(CollapsedArrowString)
Case Else
b = Convert.FromBase64String(CollapsedString)
End Select
ms.Position = 0
ms.Write(b, 0, b.Length)
CollapsedIcon = Image.FromStream(ms)
ms.Close()
'
End Sub
Public ReadOnly Property NodesVisible() As Integer
Get
' returns the number of visible nodes
Return _nodeCount
End Get
End Property
Public Property ExpanderStyle() As TreeExpanderStyle
Get
Return _expanderStyle
End Get
Set(ByVal value As TreeExpanderStyle)
If _expanderStyle <> value Then
_expanderStyle = value
' Load the expander styles and redraw
' the whole treeview
Call LoadExpanderImages()
MyBase.Invalidate()
End If
End Set
End Property
Public Property ShadedParentStyle() As Boolean
Get
Return _parentShaded
End Get
Set(ByVal value As Boolean)
_parentShaded = value
Me.Invalidate()
End Set
End Property
Public Property CollapsibleParent() As Boolean
Get
Return _collapsibleParent
End Get
Set(ByVal value As Boolean)
_collapsibleParent = value
If _collapsibleParent = True Then
' If the PARENT it collapsable then
' the parent must also be selectable
_selectableParent = True
End If
Call SetTreeviewStyle()
End Set
End Property
Public Property SelectableParent() As Boolean
Get
Return _selectableParent
End Get
Set(ByVal value As Boolean)
_selectableParent = value
If _selectableParent = False Then
'if the PARENT is NOT Selectable
' then it ca'nt be collapsable
_collapsibleParent = False
End If
Call SetTreeviewStyle()
End Set
End Property
Private Sub SetTreeviewStyle()
' ---------------------------------------------------------------------
' Sets the various Treeview settings
' ---------------------------------------------------------------------
'
MyBase.ShowRootLines = _collapsibleParent
If _collapsibleParent = False Then
' Ensure that the root nodes are expanded
For Each n As TreeNode In MyBase.Nodes
If n.IsExpanded = False Then n.Expand()
Next
End If
'
' Unselect the node if it's a parent and are not allowed
' to select parent nodes
If _selectableParent = False Then
If MyBase.SelectedNode IsNot Nothing AndAlso MyBase.SelectedNode.Level = 0 Then
MyBase.SelectedNode = Nothing
End If
End If
'
' ensure a node is selected
If MyBase.SelectedNode Is Nothing Then
For Each n As TreeNode In MyBase.Nodes
If _selectableParent Then
MyBase.SelectedNode = n
Exit For
End If
If n.IsExpanded = True Then
' Select the FIRST Node in this list
If n.Nodes.Count > 0 Then
MyBase.SelectedNode = n.Nodes(0)
Exit For
End If
End If
Next
End If
'
Dim g As Graphics = Me.CreateGraphics
Dim sz As SizeF = g.MeasureString(CollapsedString.Substring(0, 2), Me.Font, 125)
Dim newHeight As Integer = Convert.ToInt32(Math.Ceiling(sz.Height))
If newHeight > MyBase.ItemHeight Then MyBase.ItemHeight = newHeight
g.Dispose()
'
NodeBrush = New SolidBrush(Me.ForeColor)
'
End Sub
Private Sub CalculateNodes()
' ---------------------------------------------------------------------
' Calculate the current number of nodes that can be visible
' in the treeview
' ---------------------------------------------------------------------
'Dim currentCount As Integer = _nodeCount
_nodeCount = NodeRecursiveCount(MyBase.Nodes)
'If _nodeCount <> currentCount Then
' RaiseEvent NewNodeCount
'End If
End Sub
Private Function NodeRecursiveCount(ByVal nodeItems As TreeNodeCollection) As Integer
' ---------------------------------------------------------------------
' Recursive function to determine how many nodes are visible
' ---------------------------------------------------------------------
Dim count As Integer
For Each n As TreeNode In nodeItems
count += 1
If n.IsExpanded Then count += NodeRecursiveCount(n.Nodes)
Next
Return count
End Function
#Region " SHADOWED PROPERTIES "
Public Shadows Property ImageList() As ImageList
Get
Return MyBase.ImageList
End Get
Set(ByVal value As ImageList)
MyBase.ImageList = value
_haveImages = (MyBase.ImageList IsNot Nothing)
End Set
End Property
<Browsable(True), [ReadOnly](False)> _
Public Shadows Property Font() As Font
Get
Return MyBase.Font
End Get
Set(ByVal value As Font)
MyBase.Font = value
Call SetTreeviewStyle()
End Set
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property DrawMode() As TreeViewDrawMode
Get
Return MyBase.DrawMode
End Get
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property FullRowSelect() As Boolean
Get
Return MyBase.FullRowSelect
End Get
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property ShowRootLines() As Boolean
Get
Return MyBase.ShowRootLines
End Get
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property ShowLines() As Boolean
Get
Return MyBase.ShowLines
End Get
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property LabelEdit() As Boolean
Get
Return MyBase.LabelEdit
End Get
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property ShowPlusMinus() As Boolean
Get
Return MyBase.ShowPlusMinus
End Get
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property LineColor() As Color
Get
Return MyBase.LineColor
End Get
End Property
<Browsable(False), [ReadOnly](True)> _
Public Shadows ReadOnly Property CheckBoxes() As Boolean
Get
Return MyBase.CheckBoxes
End Get
End Property
#End Region
Protected Overrides Sub InitLayout()
' ---------------------------------------------------------------------
' New Treeview: Initialize the Layout
' ---------------------------------------------------------------------
MyBase.InitLayout()
'
' Overridden properties
MyBase.DrawMode = TreeViewDrawMode.OwnerDrawAll
MyBase.ShowLines = True
MyBase.FullRowSelect = True
MyBase.ShowPlusMinus = True
MyBase.ShowRootLines = True
MyBase.CheckBoxes = False
MyBase.LineColor = Color.Black
'
End Sub
Protected Overrides Sub OnAfterCollapse(ByVal e As System.Windows.Forms.TreeViewEventArgs)
' ---------------------------------------------------------------------
' After collapsing - redo the node count
' ---------------------------------------------------------------------
MyBase.OnAfterCollapse(e)
Call CalculateNodes()
End Sub
Protected Overrides Sub OnAfterExpand(ByVal e As System.Windows.Forms.TreeViewEventArgs)
' ---------------------------------------------------------------------
' After Expanding - redo the node count
' ---------------------------------------------------------------------
MyBase.OnAfterExpand(e)
Call CalculateNodes()
End Sub
Protected Overrides Sub OnParentFontChanged(ByVal e As System.EventArgs)
' ---------------------------------------------------------------------
' Override the OnParentFontChanged event
' ---------------------------------------------------------------------
MyBase.OnParentFontChanged(e)
Call SetTreeviewStyle()
End Sub
Protected Overrides Sub OnBeforeSelect(ByVal e As System.Windows.Forms.TreeViewCancelEventArgs)
' ---------------------------------------------------------------------
' Override the OnBeforeSelect event
' ---------------------------------------------------------------------
MyBase.OnBeforeSelect(e)
If _selectableParent = True Then Return
' Cannot select the PARENT Node
If e.Node.Parent Is Nothing Then e.Cancel = True
End Sub
Protected Overrides Sub OnBeforeExpand(ByVal e As System.Windows.Forms.TreeViewCancelEventArgs)
' ---------------------------------------------------------------------
' Override the OnBeforeExpand event
' ---------------------------------------------------------------------
MyBase.OnBeforeExpand(e)
MyBase.Invalidate()
If _collapsibleParent = True Then Return
' If we cannot collapse the parent,
' then ensure that a parent node isn't expanded.
If e.Node.Parent Is Nothing Then e.Cancel = True
End Sub
Protected Overrides Sub OnBeforeCollapse(ByVal e As System.Windows.Forms.TreeViewCancelEventArgs)
' ---------------------------------------------------------------------
' Override the OnBeforeCollapse event
' ---------------------------------------------------------------------
MyBase.OnBeforeCollapse(e)
MyBase.Invalidate()
If _collapsibleParent = True Then Return
' If we cannot collapse the parent,
' then ensure that a parent node isn't collapsed.
If e.Node.Parent Is Nothing Then e.Cancel = True
End Sub
Protected Overrides Sub OnPaintBackground(ByVal pevent As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaintBackground(pevent)
pevent.Graphics.DrawImage(My.Resources.VeggieBag, New Rectangle(0, 0, My.Resources.VeggieBag.Width, My.Resources.VeggieBag.Height))
End Sub
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
' ---------------------------------------------------------------------
' Override the OnPaint event to paint the nodes
' ---------------------------------------------------------------------
MyBase.OnPaint(e)
' Recalculate the number of nodes
' Note (This Could Get Sluggish)
Call CalculateNodes()
'
If Me._collapsibleParent = False Then
For Each n As TreeNode In MyBase.Nodes
If n.IsExpanded = False Then n.Expand()
Next
End If
Call PaintNodes(MyBase.Nodes, e)
End Sub
#Region " NODE DRAWING FUNCTIONS "
Private Sub PaintNodes(ByVal parentNodes As TreeNodeCollection, ByVal args As PaintEventArgs)
' ---------------------------------------------------------------------
' Paint the nodes
' ---------------------------------------------------------------------
For Each n As TreeNode In parentNodes
Dim b As New Rectangle(0, n.Bounds.Y, MyBase.ClientSize.Width, n.Bounds.Height)
If args.ClipRectangle.IntersectsWith(b) Then
' This node intersects with the clip rectangle, so draw it
b = New Rectangle(n.Bounds.X, n.Bounds.Y, MyBase.ClientSize.Width - n.Bounds.X - 1, n.Bounds.Height)
Call DrawThisNode(args.Graphics, n, b)
End If
' Check for children nodes
' (Recursively draw the nodes)
If n.Nodes.Count > 0 Then Call PaintNodes(n.Nodes, args)
Next
End Sub
Private Sub DrawThisNode(ByVal g As Graphics, ByVal node As TreeNode, ByVal rBounds As Rectangle)
' ---------------------------------------------------------------------
' Draw a specific node
' ---------------------------------------------------------------------
'
Dim selected As Boolean = node.IsSelected ' convenience
Dim yOffset As Integer = (MyBase.ItemHeight - ICON_SIZE) \ 2 ' where to draw the images
'
Dim xIcon As Integer = rBounds.X - ICON_START ' this is where the icon starts
Dim hasExpander As Boolean ' has an Expand/collaps been drawn for this node
Dim hasImage As Boolean ' has an image been drawn for this node
'
' Draw expander and image
hasExpander = DrawNodeExpander(g, node, xIcon, rBounds.Y + yOffset)
hasImage = DrawNodeImage(g, node, xIcon, rBounds.Y + yOffset)
'
' is there any space to the LEFT of the text
Dim leftWidth As Integer = xIcon + ICON_SIZE
If hasExpander Then leftWidth -= (EXPANDER_LOCATION + 1)
If hasImage Or hasExpander Then leftWidth -= ICON_START
Dim noIcons As Boolean = Not (hasExpander Or hasImage)
'
Dim rBorder As Rectangle
' Reduce the SIZE of the bounds, used for drawing rectangles
If noIcons Then
' The rectangle Bounds stretches across the full width of the control
rBorder = New Rectangle(0, rBounds.Y, rBounds.Width - 1 + rBounds.X, rBounds.Height - 1)
leftWidth = 0 ' Clear the left width value
Else
If hasImage Then
' Reduce the SIZE of the bounds, used for drawing rectangles
rBorder = New Rectangle(rBounds.X, rBounds.Y, rBounds.Width - 1, rBounds.Height - 1)
Else
' Reduce the SIZE of the bounds, used for drawing rectangles
rBorder = New Rectangle(rBounds.X - ICON_SIZE, rBounds.Y, rBounds.Width + ICON_SIZE - 1, rBounds.Height - 1)
End If
End If
'
' Highlighting/background
If node.Level = 0 And _parentShaded Then
' Draw a Shaded Parent Node
Call DrawParentNodeBackground(g, selected, leftWidth, rBorder)
Else
' Draw a child/unshaded node
Call DrawNodeBackground(g, selected, leftWidth, rBorder)
End If
'
' Draw the actual Text
Dim rText As RectangleF = DrawNodeText(g, node, rBounds)
' Draw any node customization
Call DrawNodeCustom(g, node, rText)
'
End Sub
Private Function DrawNodeImage(ByVal g As Graphics, ByVal node As TreeNode, ByVal xPosition As Integer, ByVal yPosition As Integer) As Boolean
' ---------------------------------------------------------------------
' Draw the IMAGE associated with this node
' ---------------------------------------------------------------------
If _haveImages = False Then Return False
' Have images: does this NODE have an image?
'
Dim img As Drawing.Image = Nothing ' Define an image object
'
If node.IsSelected Then
' SELECTED
If node.SelectedImageIndex >= 0 Then
img = MyBase.ImageList.Images(node.SelectedImageIndex)
ElseIf node.SelectedImageKey IsNot Nothing Then
img = MyBase.ImageList.Images(node.SelectedImageKey)
End If
Else
' NOT SELECTED
If node.ImageIndex >= 0 Then
img = MyBase.ImageList.Images(node.ImageIndex)
ElseIf node.ImageKey IsNot Nothing Then
img = MyBase.ImageList.Images(node.ImageKey)
End If
End If
If img Is Nothing Then Return False
' If an image exists, then draw this image at the correct position
g.DrawImage(img, xPosition, yPosition)
Return True
End Function
Private Function DrawNodeExpander(ByVal g As Graphics, ByVal node As TreeNode, ByVal iconLocation As Integer, ByVal yPosition As Integer) As Boolean
' ---------------------------------------------------------------------
' 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
Dim position As Integer = iconLocation - EXPANDER_LOCATION
Dim result As Boolean
If node.IsExpanded Then
' Draw the EXPANDED Icon
g.DrawImage(ExpandedIcon, position, yPosition)
result = True
Else
If node.Nodes.Count > 0 Then
' Draw the Collapsed Icon
g.DrawImage(CollapsedIcon, position, yPosition)
result = True
End If
End If
Return result ' Has an expander been drawn
End Function
Private Sub DrawParentNodeBackground(ByVal g As Graphics, ByVal selected As Boolean, ByVal wLeft As Integer, ByVal rBorder As Rectangle)
' ---------------------------------------------------------------------
' Draws the background for a PARENT Node
' ---------------------------------------------------------------------
Dim r As Rectangle
' Set the rectangle for the 'background' Gradient
r = New Rectangle(rBorder.X, rBorder.Y - 1, rBorder.Width, rBorder.Height + 4)
If r.Width < 1 Then r.Width = 1
If r.Height < 1 Then r.Height = 1
' Set the FILL Rectangle to be slightly smaller than the actual gradient rectangle
Dim rFill As New Rectangle(r.Left, rBorder.Y, r.Width, rBorder.Height - 1)
'
' Draw the gradient
Dim lgBrush As Drawing2D.LinearGradientBrush
If selected Then
' Highlight Node
lgBrush = New Drawing2D.LinearGradientBrush(r, HighlightColor, Me.BackColor, Drawing2D.LinearGradientMode.Vertical)
Else
' Normal Node
lgBrush = New Drawing2D.LinearGradientBrush(r, Me.BackColor, RootColor, Drawing2D.LinearGradientMode.Vertical)
End If
g.FillRectangle(lgBrush, rFill)
If selected Then g.DrawRectangle(HighlightBorderPen, rBorder)
'
If wLeft > 0 Then
' Draw the LEFT Rectangle if necessary
' If a rectangle is needed, then draw the rectangle
Dim leftRect As New Rectangle(0, rBorder.Y, wLeft, rBorder.Height)
g.FillRectangle(lgBrush, leftRect)
If selected Then
' Selected rectangle to the LEFT of the icons
g.DrawRectangle(HighlightBorderPen, leftRect)
End If
End If
End Sub
Private Sub DrawNodeBackground(ByVal g As Graphics, ByVal selected As Boolean, ByVal wLeft As Integer, ByVal rBorder As Rectangle)
' ---------------------------------------------------------------------
' Draws the background for a REGULAR Node
' ---------------------------------------------------------------------
If Not selected Then Return ' Nothing to draw
'
' Highlight either the FULL row, or to the right of the icons
g.FillRectangle(HighlightBrush, rBorder)
g.DrawRectangle(HighlightBorderPen, rBorder)
'
If wLeft > 0 Then
' Draw the LEFT Rectangle
Dim leftRect As New Rectangle(0, rBorder.Y, wLeft, rBorder.Height)
g.FillRectangle(HighlightBrush, leftRect)
g.DrawRectangle(HighlightBorderPen, leftRect)
End If
End Sub
Private Function DrawNodeText(ByVal g As Graphics, ByVal node As TreeNode, ByVal rBounds As Rectangle) As RectangleF
' ---------------------------------------------------------------------
' Draw the actual node text
' Returns a rectangle where the text was drawn
' ---------------------------------------------------------------------
Dim txt As String = node.Text
Dim sz As SizeF = g.MeasureString(txt, Me.Font, rBounds.Width, TextFormat)
Dim textBounds As New RectangleF(rBounds.X, rBounds.Y + Convert.ToInt32((rBounds.Height - sz.Height) / 2), rBounds.Width, Convert.ToInt32(sz.Height))
g.DrawString(node.Text, Me.Font, NodeBrush, textBounds, TextFormat)
' Return the rectanglewhere the text was drawn
textBounds.Width = sz.Width
Return textBounds
End Function
Private Sub DrawNodeCustom(ByVal g As Graphics, ByVal node As TreeNode, ByVal rText As RectangleF)
' ---------------------------------------------------------------------
' Draw a CUSTOM Node if it's been supplied
' ---------------------------------------------------------------------
Dim n As CustomNode = TryCast(node, CustomNode)
If n Is Nothing Then Return ' Nothing is customized
'
' Draw the CUSTOM Properties for this node
Dim br As Brush
' Get the Post-text color
Dim col As Color = n.PostTextColor
' If there isn't a color, use the derault color
If col.IsEmpty Then
br = NodeBrush
Else
br = New SolidBrush(n.PostTextColor)
End If
g.DrawString(String.Format(Globalization.CultureInfo.CurrentUICulture, " {0}", n.PostText), Me.Font, br, rText.X + rText.Width, rText.Y)
End Sub
#End Region
End Class
<Serializable()> Public Class CustomNode : Inherits TreeNode
Private _postText As String
Private _postTextColor As Color
Private _postTextShow As Boolean
Protected Sub New(ByVal info As System.Runtime.Serialization.SerializationInfo, _
ByVal context As System.Runtime.Serialization.StreamingContext)
' ---------------------------------------------------------------------
' Constructor for Serialization
' ---------------------------------------------------------------------
Call MyBase.New(info, context)
End Sub
Public Sub New()
_postTextColor = Color.Empty
_postTextShow = True
_postText = String.Empty
End Sub
Public Property PostText() As String
Get
Return _postText
End Get
Set(ByVal value As String)
_postText = value
Call ForceUpdate()
End Set
End Property
Public Property PostTextColor() As Color
Get
Return _postTextColor
End Get
Set(ByVal value As Color)
_postTextColor = value
Call ForceUpdate()
End Set
End Property
Public Property PostTextShow() As Boolean
Get
Return _postTextShow
End Get
Set(ByVal value As Boolean)
_postTextShow = value
Call ForceUpdate()
End Set
End Property
Private Sub ForceUpdate()
' ---------------------------------------------------------------------
' Force a change in the node text to update the
' node in the parent treeview
' Rather crude, but appears to work
' ---------------------------------------------------------------------
MyBase.Text = MyBase.Text
End Sub
End Class